Ответ
Буферизированный канал в Go работает по принципу FIFO (First-In, First-Out), то есть как классическая очередь.
- Отправка (
ch <- value
): Новое значение всегда добавляется в конец очереди (буфера). - Чтение (
<- ch
): Значение всегда извлекается из начала очереди (буфера).
Поведение:
- Отправка: Если буфер не заполнен (
len(ch) < cap(ch)
), отправка происходит немедленно и без блокировки. Если буфер полон, отправляющая горутина блокируется до тех пор, пока другая горутина не прочитает значение из канала и не освободит место. - Чтение: Если буфер не пуст (
len(ch) > 0
), чтение происходит немедленно. Если буфер пуст, читающая горутина блокируется, пока в канал не будет отправлено новое значение.
Пример:
package main
import "fmt"
func main() {
// Создаем канал с буфером на 3 элемента
ch := make(chan int, 3)
// Отправляем значения. Они добавляются в конец очереди.
ch <- 1 // Канал: [1], len=1, cap=3
ch <- 2 // Канал: [1, 2], len=2, cap=3
ch <- 3 // Канал: [1, 2, 3], len=3, cap=3
// Канал полон. Следующая отправка заблокировала бы горутину.
// ch <- 4 // fatal error: all goroutines are asleep - deadlock!
// Читаем значения. Они извлекаются из начала очереди.
fmt.Println(<-ch) // Выведет: 1. Канал: [2, 3], len=2, cap=3
fmt.Println(<-ch) // Выведет: 2. Канал: [3], len=1, cap=3
// Можно снова отправлять, т.к. место освободилось
ch <- 5 // Канал: [3, 5], len=2, cap=3
fmt.Println(<-ch) // Выведет: 3
fmt.Println(<-ch) // Выведет: 5
}