Модульні уроки (2/5)
Канали: типізований зв'язок
Канали – це ідіоматичний механізм зв’язку між goroutines. Філософія Go (Роб Пайк):
«Не спілкуйтеся, ділячись пам’яттю; діліться пам’яттю, спілкуючись».
Канал — це типова черга FIFO, безпечна для типу та безпечна для одночасного використання
використовувати. У поєднанні з 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
ch := make(chan int, 3)
ch <- 1 // non blocca
ch <- 2 // non blocca
ch <- 3 // non blocca
ch <- 4 // BLOCCA: il buffer è pienoВідправник блокує лише тоді, коли буфер заповнений; тільки приймач коли він порожній.
впритул і далеко
Відправник закриває канал, коли більше немає значень:
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 над каналом повторюється, доки канал не буде закрито (і опорожнено).
Це найчистіший шаблон «споживай все, що надходить».
Спрямованість у підписах
Параметри функції можуть обмежувати напрямок:
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{}закрито для сигналу "стоп".
done := make(chan struct{})
go func() {
<-done // blocca finché qualcuno chiude done
cleanup()
}()
close(done) // segnale di stopchan struct{} є каналом "сигналу": нуль байтів корисного навантаження, просто
синхронізація.
Спробуйте
Створіть небуферизований канал int ch, надішліть 42 із goroutine, отримайте в main і надрукуйте його.
Показати підказку
Без буфера відправник і одержувач синхронізуються.
Рішення доступне після 3 спроб
Надішліть 1,2,3 через буферизований канал, закрийте його, а потім надрукуйте все за допомогою for-range.
Показати підказку
`for range` над каналом закінчується, коли канал закривається та осушується.
Рішення доступне після 3 спроб
Що робить канал UNBUFFERED, коли відправник надсилає, але одержувач не готовий?
ch := make(chan int)
ch <- 1 // ?Підведення підсумків
- Канал = введена черга FIFO, безпечна між go-програмами.
- Без буферизації: рандеву (відправник і одержувач синхронізуються).
- Буферизований: розв'язування, блокує лише коли повний/порожній.
close(ch): лише відправник;for rangeвитрачається до закриття.- Спрямованість:
chan<- T(лише надсилання),<-chan T(лише отримання). chan struct{}як канал сигналу для чистої синхронізації.