Канал-рандеву
Сергей поручил Мише конвейер загрузки — цепочку шагов, где один принимает файл, другой разбирает, третий сохраняет. Миша собрал первый набросок: каждый шаг передавал результат следующему, и цепочка впервые заработала целиком. Это была первая система, которую он не просто писал, а проектировал.
небуферизованный канал — это рандеву: отправка блокируется, пока другая горутина не примет значение, поэтому сам факт приёма — синхронизация.
Отправка и приём встречаются
next := make(chan File)
go func() { // следующий шаг конвейера
f := <-next // заблокируется, пока предыдущий шаг не отдаст файл
save(f)
}()
next <- file // разблокирует приём
Канал создаётся через make(chan T). Отправка ch <- v и приём <-ch — парные операции: небуферизованный канал передаёт значение только в момент, когда обе стороны готовы. Отправитель ждёт получателя, получатель ждёт отправителя — отсюда и «рандеву». Шаг конвейера не «кладёт» работу следующему, а передаёт её из рук в руки.
Отправка блокируется до приёма
ch := make(chan int)
ch <- 1 // заблокируется навсегда: принимать некому
fmt.Println("не дойдёт")
Отправка в небуферизованный канал без готового получателя — вечная блокировка (вспомни утечки горутин,). Это не ошибка: канал — инструмент синхронизации, и «ждать» — его работа.
Канал как сигнал
Самое чистое применение небуферизованного канала — сигнал «шаг завершился»:
done := make(chan struct{})
go func() {
processFiles()
close(done) // или done <- struct{}{}
}()
<-done // ждём завершения шага
struct{} — тип нулевого размера для сигналов: пустое значение, никаких данных. Закрытие канала — отдельный приём, но уже здесь видно: канал — это и передача данных, и синхронизация в одном инструменте.
Вы узнаете:
- как happens-before работает у небуферизованного канала
- как работают направленные каналы
Небуферизованный канал — рандеву: передача в момент встречи. Отправка без получателя блокирует. Канал — и данные, и синхронизация.
10 000 ₽ · 60 минут · онлайн