В каких случаях блокируется буферизованный канал?

Ответ

Буферизованный канал (созданный с размером больше 0, например make(chan int, 100)) блокирует горутину в двух ситуациях:


  1. При отправке в переполненный канал.

    Если буфер канала уже заполнен (в нем находится 100 элементов), следующая операция отправки ch <- value заблокирует текущую горутину до тех пор, пока другая горутина не освободит место, прочитав данные из канала.



  2. При чтении из пустого канала.

    Если буфер канала пуст, операция чтения <-ch заблокирует текущую горутину до тех пор, пока другая горутина не отправит данные в этот канал.


Примеры блокировок:

package main

import (
    "fmt"
    "time"
)

func main() {
    // Канал с буфером на 3 элемента
    ch := make(chan int, 3)

    // --- Сценарий 1: Блокировка при отправке --- 
    fmt.Println("Заполняем буфер...")
    ch <- 1
    ch <- 2
    ch <- 3
    fmt.Println("Буфер полон. Следующая отправка заблокируется.")

    go func() {
        time.Sleep(2 * time.Second)
        value := <-ch // Через 2 секунды освобождаем место
        fmt.Printf("nПрочитано значение: %dn", value)
    }()

    ch <- 4 // Эта строка заблокирует выполнение main на 2 секунды
    fmt.Println("Отправка значения 4 разблокирована и завершена.")

    // --- Сценарий 2: Блокировка при чтении ---
    // К этому моменту в канале [2, 3, 4]
    <-ch // Читаем 2
    <-ch // Читаем 3
    <-ch // Читаем 4
    fmt.Println("nКанал пуст. Следующее чтение заблокируется.")

    go func() {
        time.Sleep(2 * time.Second)
        ch <- 5 // Через 2 секунды отправляем значение
        fmt.Println("nОтправлено значение 5 в канал")
    }()

    value := <-ch // Эта строка заблокирует выполнение main на 2 секунды
    fmt.Printf("Чтение разблокировано. Прочитано значение: %dn", value)
}

Для сравнения, небуферизованный канал (make(chan int)) — это частный случай буферизованного с размером 0. Он блокируется при каждой операции отправки или чтения, пока на другом конце не будет готова принимающая или отправляющая сторона.