Какое поведение у буферизированного канала при чтении из него, когда он пуст?

Ответ

Чтение из пустого буферизированного канала блокирует текущую горутину до тех пор, пока другой горутиной в канал не будет отправлено значение.

Это ключевое отличие от небуферизированного канала, который блокирует горутину-отправителя до тех пор, пока горутина-получатель не будет готова принять значение. В буферизированном канале отправка не блокируется, пока в буфере есть свободное место.

Пример блокировки при чтении:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    // Канал с буфером на 2 элемента
    ch := make(chan int, 2)
    var wg sync.WaitGroup

    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println("Горутина пытается прочитать из пустого канала...")
        val := <-ch // <-- Блокировка здесь, т.к. канал пуст
        fmt.Printf("Горутина успешно прочитала значение: %dn", val)
    }()

    fmt.Println("Основная программа ждет 2 секунды...")
    time.Sleep(2 * time.Second)

    fmt.Println("Основная программа отправляет значение в канал...")
    ch <- 42 // Отправка значения разблокирует читающую горутину

    wg.Wait() // Ожидаем завершения горутины
}

Чтение из закрытого канала

Если канал закрыт и пуст, операция чтения немедленно вернет нулевое значение для типа данных канала, а второй параметр ok будет false.

ch := make(chan int, 1)
ch <- 100
close(ch)

val, ok := <-ch // val = 100, ok = true (читаем последнее значение из буфера)
val, ok = <-ch // val = 0, ok = false (канал пуст и закрыт)