Lecții din modul (2/5)
Canale: comunicare tipizată
Canalele sunt mecanismul idiomatic de comunicare între gorutine. Filosofia Go (Rob Pike):
„Nu comunica prin partajarea memoriei; partajarea memoriei prin comunicare.”
Un canal este o coadă FIFO scrisă, sigură de tip și sigură pentru simultan
folosi. Combinat cu go, este blocul principal al Go
concurenta.
Creați, trimiteți, primiți
ch := make(chan int) // canale di int, unbuffered
go func() {
ch <- 42 // invia (può bloccare)
}()
v := <-ch // ricevi (può bloccare)
fmt.Println(v) // 42Sintaxă:
make(chan T)saumake(chan T, N)pentru tampon.ch <- vtrimite.v := <-chprimește.v, ok := <-chprimește cu un steag (ok = falsedacă canalul este închis ȘI gol).
Unbuffered: întâlnire
Un canal fără tampon (capacitate 0) blochează:
- emițătorul până când un receptor este gata;
- receptorul până când un expeditor este gata.
Este o programare sincronă: utilă ca „semnal” sau pentru a garanta că valoarea a fost livrată.
Buffered: coadă până la N
ch := make(chan int, 3)
ch <- 1 // non blocca
ch <- 2 // non blocca
ch <- 3 // non blocca
ch <- 4 // BLOCCA: il buffer è pienoExpeditorul se blochează numai când tamponul este plin; numai receptorul când este gol.
aproape și la distanță
Expeditorul închide canalul când nu mai există valori:
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 peste un canal se repetă până când canalul este închis (și golit).
Este cel mai curat tipar pentru „consuma tot ce ajunge”.
Direcționalitatea în semnături
Parametrii funcției pot restricționa direcția:
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 = numai pentru trimitere, <-chan T = numai pentru primire. Un bidirecțional
canalul chan T poate fi transmis fie la oricare (conversie implicită). Ea
îmbunătățește claritatea și previne greșelile.
Modele comune (previzualizare)
- Grup de lucrători: N gorutine consumă din
jobs <-chan T, produc peresults chan<- R. - Pipeline: etape conectate prin canale.
- Semnal gata: un canal
chan struct{}închis pentru a semnala „oprire”.
done := make(chan struct{})
go func() {
<-done // blocca finché qualcuno chiude done
cleanup()
}()
close(done) // segnale di stopchan struct{} este canalul „semnal”: zero octeți de sarcină utilă, doar
sincronizare.
Încearcă
Creați un canal int fără buffer, trimiteți 42 dintr-o rutină, primiți în principal și imprimați-l.
Afișează indiciu
Fără un buffer, expeditorul și receptorul se sincronizează.
Soluție disponibilă după 3 încercări
Trimiteți 1,2,3 pe un canal tamponat, închideți-l, apoi imprimați totul cu for-range.
Afișează indiciu
„pentru rază” peste un canal se termină când canalul este închis și golit.
Soluție disponibilă după 3 încercări
Ce face un canal UNBUFFERED când expeditorul trimite, dar niciun receptor nu este pregătit?
ch := make(chan int)
ch <- 1 // ?Recapitulare
- Canal = coada FIFO tastata, sigur intre rutine.
- Unbuffered: rendezvous (se sincronizează expeditorul și receptorul).
- Buffered: decuplare, se blochează numai când este plin/gol.
close(ch): doar expeditorul;for rangeconsumă până la închidere.- Direcționalitate:
chan<- T(numai pentru trimitere),<-chan T(numai pentru primire). chan struct{}ca canal de semnal pentru sincronizare pură.