Salt la conținutul principal
Modulul 7 · Lecția 2 din 532/50 în curs~15 min
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

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

Sintaxă:

  • make(chan T) sau make(chan T, N) pentru tampon.
  • ch <- v trimite.
  • v := <-ch primește.
  • v, ok := <-ch primește cu un steag (ok = false dacă 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

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

Expeditorul 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:

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 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:

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 = 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 pe results chan<- R.
  • Pipeline: etape conectate prin canale.
  • Semnal gata: un canal chan struct{} închis pentru a semnala „oprire”.
Go
done := make(chan struct{})
go func() {
    <-done    // blocca finché qualcuno chiude done
    cleanup()
}()
close(done)   // segnale di stop

chan struct{} este canalul „semnal”: zero octeți de sarcină utilă, doar sincronizare.

Încearcă

Exercițiu#go.m7.l2.e1
Încercări: 0Se încarcă…

Creați un canal int fără buffer, trimiteți 42 dintr-o rutină, primiți în principal și imprimați-l.

Se încarcă editorul...
Afișează indiciu

Fără un buffer, expeditorul și receptorul se sincronizează.

Soluție disponibilă după 3 încercări

Exercițiu#go.m7.l2.e2
Încercări: 0Se încarcă…

Trimiteți 1,2,3 pe un canal tamponat, închideți-l, apoi imprimați totul cu for-range.

Se încarcă editorul...
Afișează indiciu

„pentru rază” peste un canal se termină când canalul este închis și golit.

Soluție disponibilă după 3 încercări

Quiz#go.m7.l2.e3
Gata

Ce face un canal UNBUFFERED când expeditorul trimite, dar niciun receptor nu este pregătit?

Go
ch := make(chan int)
ch <- 1 // ?
Opțiuni de răspuns

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 range consumă 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ă.