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

Канали: типізований зв'язок

Канали – це ідіоматичний механізм зв’язку між goroutines. Філософія Go (Роб Пайк):

«Не спілкуйтеся, ділячись пам’яттю; діліться пам’яттю, спілкуючись».

Канал — це типова черга 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 goroutines споживають з 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 із goroutine, отримайте в main і надрукуйте його.

Завантаження редактора…
Показати підказку

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

Рішення доступне після 3 спроб

вправи#go.m7.l2.e2
Спроби: 0Завантаження…

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

Завантаження редактора…
Показати підказку

`for range` над каналом закінчується, коли канал закривається та осушується.

Рішення доступне після 3 спроб

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

Що робить канал UNBUFFERED, коли відправник надсилає, але одержувач не готовий?

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

Підведення підсумків

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