Modulelessen (2/5)
Kanalen: getypte communicatie
Kanalen zijn het idiomatische mechanisme voor communicatie tussen goroutines. De Go-filosofie (Rob Pike):
"Communiceer niet door herinneringen te delen; deel herinneringen door te communiceren."
Een kanaal is een getypeerde FIFO-wachtrij, typeveilig en veilig voor gelijktijdig gebruik
gebruik. Gecombineerd met go is dit de belangrijkste bouwsteen van Go
gelijktijdigheid.
Maken, verzenden, ontvangen
ch := make(chan int) // canale di int, unbuffered
go func() {
ch <- 42 // invia (può bloccare)
}()
v := <-ch // ricevi (può bloccare)
fmt.Println(v) // 42Syntaxis:
make(chan T)ofmake(chan T, N)voor gebufferd.ch <- vverzendt.v := <-chontvangt.v, ok := <-chontvangt met een vlag (ok = falseals het kanaal gesloten EN leeg is).
Ongebufferd: rendez-vous
Een ongebufferd kanaal (capaciteit 0) blokkeert:
- de zender totdat een ontvanger gereed is;
- de ontvanger totdat er een afzender klaar is.
Het is een synchrone afspraak: handig als ‘signaal’ of om te garanderen dat de waarde is geleverd.
Gebufferd: wachtrij tot N
ch := make(chan int, 3)
ch <- 1 // non blocca
ch <- 2 // non blocca
ch <- 3 // non blocca
ch <- 4 // BLOCCA: il buffer è pienoDe afzender blokkeert alleen als de buffer vol is; alleen de ontvanger wanneer deze leeg is.
dichtbij en binnen bereik
De afzender sluit het kanaal als er geen waarden meer zijn:
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 over een kanaal herhaalt zich totdat het kanaal is gesloten (en leeggemaakt).
Het is het schoonste patroon voor ‘consumeer alles wat binnenkomt’.
Directionaliteit in handtekeningen
Functieparameters kunnen de richting beperken:
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 = alleen verzenden, <-chan T = alleen ontvangen. Een bidirectioneel
kanaal chan T kan aan beide worden doorgegeven (impliciete conversie). Het
verbetert de duidelijkheid en voorkomt fouten.
Algemene patronen (preview)
- Werknemerspool: N goroutines consumeren van
jobs <-chan T, produceren opresults chan<- R. - Pipeline: podia verbonden door kanalen.
- Klaar signaal: een
chan struct{}kanaal gesloten om "stop" aan te geven.
done := make(chan struct{})
go func() {
<-done // blocca finché qualcuno chiude done
cleanup()
}()
close(done) // segnale di stopchan struct{} is het signaalkanaal: nul bytes aan payload, slechts
synchronisatie.
Probeer het
Maak een ongebufferd int-kanaalch, verzend 42 vanaf een goroutine, ontvang in het hoofdkanaal en druk het af.
Toon hint
Zonder buffer synchroniseren zender en ontvanger.
Oplossing beschikbaar na 3 pogingen
Stuur 1,2,3 via een gebufferd kanaal, sluit het en druk alles af met for-range.
Toon hint
'voor bereik' over een kanaal eindigt wanneer het kanaal gesloten en drooggelegd is.
Oplossing beschikbaar na 3 pogingen
Wat doet een ONGEBUFFERD kanaal als de zender zendt maar er geen ontvanger gereed is?
ch := make(chan int)
ch <- 1 // ?Samenvatten
- Kanaal = getypte FIFO-wachtrij, veilig tussen goroutines.
- Ongebufferd: rendez-vous (zender en ontvanger synchroniseren).
- Gebufferd: ontkoppeling, blokkeert alleen bij vol/leeg.
close(ch): alleen de afzender;for rangeconsumeert tot sluitingstijd.- Directionaliteit:
chan<- T(alleen verzenden),<-chan T(alleen ontvangen). chan struct{}als signaalkanaal voor pure synchronisatie.