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

Ответ

Да, при создании канала можно не указывать его размер. Такой канал называется небуферизированным (или синхронным).

// Небуферизированный канал
ch := make(chan int)

// Буферизированный канал размером 5
// bufferedCh := make(chan int, 5)

Принцип работы небуферизированного канала:

Он работает по принципу рандеву. Это означает, что операция отправки и операция получения данных должны произойти одновременно.

  • Горутина, отправляющая данные (ch <- data), будет заблокирована до тех пор, пока другая горутина не будет готова принять эти данные (<-ch).
  • И наоборот, горутина, читающая данные, будет заблокирована, пока другая горутина не отправит в него данные.

Это делает небуферизированные каналы идеальным инструментом для синхронизации двух горутин.

Пример синхронизации:

package main

import (
    "fmt"
    "time"
)

func main() {
    done := make(chan bool) // Небуферизированный канал для сигнала

    go func() {
        fmt.Println("Рабочая горутина начала работу...")
        time.Sleep(2 * time.Second)
        fmt.Println("Рабочая горутина закончила работу.")
        done <- true // Отправляем сигнал о завершении. Блокируемся, пока main не прочитает.
    }()

    // Основная горутина блокируется здесь, ожидая сигнала из канала done.
    <-done 
    fmt.Println("Основная горутина получила сигнал и завершается.")
}

Ключевое отличие от буферизированного канала:

Буферизированный канал (make(chan int, N)) имеет внутренний буфер. Отправляющая горутина блокируется только тогда, когда буфер полон. Читающая горутина блокируется только тогда, когда буфер пуст. Это позволяет осуществлять асинхронную коммуникацию без немедленной синхронизации.