Ответ
Небуферизированный канал — это канал с нулевой ёмкостью (make(chan T)
). Его главная особенность — гарантированная синхронизация между отправителем и получателем.
Принцип работы (Рандеву):
Операция отправки в небуферизированный канал (ch <- data
) блокирует горутину-отправителя до тех пор, пока другая горутина не будет готова принять данные из этого канала (<-ch
). Аналогично, операция чтения блокирует горутину-получателя, пока кто-то не отправит данные.
ch := make(chan int) // Небуферизированный канал
go func() {
fmt.Println("Горутина: готовлюсь отправить данные...")
ch <- 42 // Блокируется здесь, пока main не будет готова прочитать
fmt.Println("Горутина: данные отправлены!")
}()
fmt.Println("Main: жду данные...")
<-ch // Блокируется здесь, пока горутина не отправит данные
fmt.Println("Main: данные получены!")
Ключевые свойства и сценарии использования:
-
Гарантия доставки: Когда отправка в небуферизированный канал завершена, отправитель имеет 100% гарантию, что данные были получены другой горутиной. Это отличает их от буферизованных каналов, где отправка лишь означает, что данные помещены в буфер.
-
Синхронизация и сигнализация: Они идеально подходят для координации действий между горутинами. Например, одна горутина может сигнализировать другой о завершении своей работы, отправив пустое значение
struct{}
.- Пример: Завершение работы воркера.
done := make(chan struct{}) go worker(done) <-done // Ожидаем, пока воркер не завершит работу и не отправит сигнал
- Пример: Завершение работы воркера.
-
Предотвращение состояний гонки: Поскольку передача данных синхронизирована, это естественный способ избежать гонок без использования мьютексов.
Опасность: Основной риск — deadlock. Если горутина пытается отправить данные, но никто никогда не будет их читать (или наоборот), программа зависнет с ошибкой fatal error: all goroutines are asleep - deadlock!
.