Перейти к основному содержимому
Модуль 7 · Урок 2 из 532/50 в курсе~15 min
Уроки модуля (2/5)

Каналы: типизированное общение

Каналы – это идиоматический механизм связи между горутины. Философия Го (Роб Пайк):

«Не общайтесь, делясь воспоминаниями; делитесь воспоминаниями, общаясь».

Канал — это типизированная очередь FIFO, типобезопасная и безопасная для одновременной обработки. использовать. В сочетании с go это основной строительный блок Go. параллелизм.

Создать, отправить, получить

Go
ch := make(chan int)     // canale di int, unbuffered

go func() {
    ch <- 42             // invia (può bloccare)
}()

v := <-ch                // ricevi (può bloccare)
fmt.Println(v)           // 42

Синтаксис:

  • make(chan T) или make(chan T, N) для буферизации.
  • ch <- v отправляет.
  • v := <-ch получает.
  • v, ok := <-ch получает с флагом (ok = false, если канал закрыт И пуст).

Без буферизации: рандеву

Небуферизованный канал (емкость 0) блокирует:

  • отправителя до готовности получателя;
  • получатель, пока отправитель не будет готов.

Это синхронное назначение: полезно в качестве «сигнала» или для гарантии что значение было доставлено.

Буферизовано: очередь до N

Go
ch := make(chan int, 3)
ch <- 1   // non blocca
ch <- 2   // non blocca
ch <- 3   // non blocca
ch <- 4   // BLOCCA: il buffer è pieno

Отправитель блокируется только тогда, когда буфер заполнен; только приемник когда он пуст.

близко и на расстоянии

Отправитель закрывает канал, когда значений больше нет:

Go
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)

for v := range ch {      // termina quando ch è chiuso E vuoto
    fmt.Println(v)
}

for range по каналу выполняется до тех пор, пока канал не будет закрыт (и опорожнен). Это самый чистый шаблон «поедать все, что попадает».

Направленность в подписях

Параметры функции могут ограничивать направление:

Go
func producer(out chan<- int) {   // solo invio
    out <- 1
    close(out)
}

func consumer(in <-chan int) {    // solo ricezione
    for v := range in {
        fmt.Println(v)
    }
}

chan<- T = только отправка, <-chan T = только получение. Двунаправленный канал chan T можно передать любому из них (неявное преобразование). Это улучшает ясность и предотвращает ошибки.

Общие шаблоны (предварительный просмотр)

  • Рабочий пул: N горутин потребляют данные из jobs <-chan T, производят results chan<- R.
  • Конвейер: этапы, соединенные каналами.
  • Сигнал завершения: канал chan struct{} закрыт для сигнала «стоп».
Go
done := make(chan struct{})
go func() {
    <-done    // blocca finché qualcuno chiude done
    cleanup()
}()
close(done)   // segnale di stop

chan struct{} — это «сигнальный» канал: ноль байт полезной нагрузки, всего лишь синхронизация.

Попробуйте это

Упражнение#go.m7.l2.e1
Попыток: 0Загрузка…

Создайте небуферизованный int-канал ch, отправьте 42 из горутины, получите в main и распечатайте его.

Загрузка редактора…
Показать подсказку

Без буфера отправитель и получатель синхронизируются.

Решение доступно после 3 попыток

Упражнение#go.m7.l2.e2
Попыток: 0Загрузка…

Отправьте 1,2,3 через буферизованный канал, закройте его, затем распечатайте все с помощью for-range.

Загрузка редактора…
Показать подсказку

`for range` по каналу заканчивается, когда канал закрывается и опорожняется.

Решение доступно после 3 попыток

Quiz#go.m7.l2.e3
Готово

Что делает НЕБУФЕРИРОВАННЫЙ канал, когда отправитель отправляет, но получатель не готов?

Go
ch := make(chan int)
ch <- 1 // ?
Варианты ответа

Резюме

  • Канал = типизированная очередь FIFO, безопасная между горутинами.
  • Без буферизации: рандеву (синхронизация отправителя и получателя).
  • Буферизовано: развязка, блокируется только при заполнении/пустоте.
  • close(ch): только отправитель; for range потребляет до закрытия.
  • Направленность: chan<- T (только отправка), <-chan T (только прием).
  • chan struct{} как сигнальный канал для чистой синхронизации.