Что такое размер буфера канала?

86

Я пытаюсь создать асинхронный канал, и я смотрел http://golang.org/ref/spec#Making_slices_maps_and_channels .

c := make(chan int, 10)         // channel with a buffer size of 10

Что значит размер буфера 10? Что конкретно представляет / ограничивает размер буфера?

Техника163
источник
Смотрите здесь и далее
Иван Черный
Смотрите здесь также полезно. Очень прямо и легко для понимания :)
Арди Нусаван

Ответы:

161

Размер буфера - это количество элементов, которые могут быть отправлены в канал без блокировки отправки. По умолчанию канал имеет размер буфера 0 (вы получаете это с make(chan int)). Это означает, что каждая отправка будет блокироваться до тех пор, пока другая горутина не получит из канала. Канал с размером буфера 1 может содержать 1 элемент до отправки блоков, поэтому вы получите

c := make(chan int, 1)
c <- 1 // doesn't block
c <- 2 // blocks until another goroutine receives from the channel
Лили Баллард
источник
21
Хороший ответ. В Effective Go есть хорошая глава под названием «Параллелизм», в которой подробно рассматриваются каналы. Настоятельно рекомендуется: golang.org/doc/effective_go.html
Леви,
Я возился с этим, и make (chan int, 1) позволяет передавать 3 значения в мой канал перед блокировкой (тестируя его с помощью log.Printlns), а по умолчанию допускает 2 значения до блокировки. Есть идеи, почему:
Маурисио
@Mauricio Звучит довольно странно. Я только что тестировал использование Go 1.8.3 локально, а также использовал функцию «Попробовать Go» на golang.org , и в обоих случаях он по-прежнему ведет себя так, как описано в моем ответе.
Лили Баллард,
1
Я ценю ответ, но на самом деле я неправильно истолковал вывод данных на консоль. Это работает так, как вы описали.
Маурисио
10

Следующий код иллюстрирует блокировку небуферизованного канала:

// to see the diff, change 0 to 1
c := make(chan struct{}, 0)
go func() {
    time.Sleep(2 * time.Second)
    <-c
}()
start := time.Now()
c <- struct{}{} // block, if channel size is 0
elapsed := time.Since(start)
fmt.Printf("Elapsed: %v\n", elapsed)

Вы можете поиграть с кодом здесь .

Владимир Бауэр
источник
0
package main

import (
    "fmt"
    "time"
)

func receiver(ch <-chan int) {
    time.Sleep(500 * time.Millisecond)
    msg := <-ch
    fmt.Printf("receive messages  %d from the channel\n", msg)
}

func main() {
    start := time.Now()
    zero_buffer_ch := make(chan int, 0)
    go receiver(zero_buffer_ch)
    zero_buffer_ch <- 444
    elapsed := time.Since(start)    
    fmt.Printf("Elapsed using zero_buffer channel: %v\n", elapsed)

    restart := time.Now()
    non_zero_buffer_ch := make(chan int, 1)
    go receiver(non_zero_buffer_ch)
    non_zero_buffer_ch <- 4444
    reelapsed := time.Since(restart)
    fmt.Printf("Elapsed using non zero_buffer channel: %v\n", reelapsed)
}

результат:

получать сообщения 444 с канала

Прошло с использованием канала zero_buffer: 505,6729 мс

Прошло с использованием канала, отличного от zero_buffer: 0 с

user2480972
источник