Что такое синхронные (небуферизованные) каналы в Go и в чем их отличие от асинхронных (буферизованных)?

Ответ

Синхронный (или небуферизованный) канал в Go — это канал, созданный без указания емкости буфера: make(chan T).

Его ключевая особенность — блокировка операций отправки и получения до тех пор, пока на другом конце канала не будет готова парная операция. Этот механизм называется "рандеву" (rendezvous), так как отправитель и получатель должны "встретиться" для совершения обмена данными.

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

Пример:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int) // Синхронный канал

    go func() {
        fmt.Println("Горутина: готова отправить данные")
        ch <- 42 // Эта операция заблокируется, пока main не будет готова принять
        fmt.Println("Горутина: данные успешно отправлены")
    }()

    time.Sleep(1 * time.Second) // Даем горутине время запуститься
    fmt.Println("Main: готов принять данные")
    val := <-ch // Разблокирует горутину-отправителя
    fmt.Printf("Main: данные приняты: %dn", val)
}

Ключевые отличия от буферизованных каналов

ХарактеристикаСинхронный канал (make(chan T))Буферизованный канал (make(chan T, N))
Емкость0N > 0
Блокировка отправкиВсегда, до появления получателя.Только когда буфер полон.
Блокировка полученияВсегда, до появления отправителя.Только когда буфер пуст.
Основное назначениеСинхронизация горутин, гарантированная передача данных.Буферизация данных, сглаживание разницы в скорости между производителем и потребителем.

Синхронные каналы часто используются для сигнализации о завершении работы или для управления потоком выполнения, когда важно знать, что сигнал был получен.