Canali non bufferizzati
Passaggio sincrono tra goroutine
Canali non bufferizzati è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Go Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Go Academy include 4 lezioni in totale.
Che cos'è un canale?
Un canale è un mezzo tipizzato per comunicare tra goroutine. I canali seguono il principio di Go: Non comunicate condividendo la memoria; condividete la memoria comunicando.
package main
import "fmt"
func main() {
ch := make(chan int) // unbuffered int channel
go func() {
ch <- 42 // send: blocks until someone receives
}()
v := <-ch // receive: blocks until someone sends
fmt.Println(v) // 42
}Semantica dei canali senza buffer
Un canale senza buffer non ha capacità. Un invio si blocca finché un ricevitore non è pronto, mentre una ricezione si blocca finché un mittente non invia. Questo garantisce un passaggio sincrono:
package main
import "fmt"
func double(in <-chan int, out chan<- int) {
for v := range in {
out <- v * 2
}
close(out)
}
func main() {
in := make(chan int)
out := make(chan int)
go double(in, out)
go func() { in <- 3; in <- 5; close(in) }()
for v := range out { fmt.Println(v) }
// 6
// 10
}Canale per la sincronizzazione
I canali senza buffer sincronizzano le goroutine: li utilizzi come segnale che indica il completamento del lavoro:
package main
import "fmt"
func compute(result chan<- int) {
sum := 0
for i := 1; i <= 100; i++ { sum += i }
result <- sum
}
func main() {
ch := make(chan int)
go compute(ch)
fmt.Println("Result:", <-ch) // blocks until compute sends
}Chiusura di un canale
Il mittente chiude un canale con close(ch) per segnalare che non verranno inviati altri valori. I ricevitori rilevano la chiusura tramite la forma a due valori:
package main
import "fmt"
func generate(ch chan<- int, max int) {
for i := 0; i < max; i++ {
ch <- i
}
close(ch) // signal done
}
func main() {
ch := make(chan int)
go generate(ch, 5)
for v := range ch { // range detects close automatically
fmt.Println(v)
}
fmt.Println("channel closed")
}Ricezione a due valori
La ricezione a due valori v, ok := <-ch indica se il canale è ancora aperto:
package main
import "fmt"
func main() {
ch := make(chan string, 1)
ch <- "hello"
close(ch)
v1, ok1 := <-ch
fmt.Println(v1, ok1) // hello true
v2, ok2 := <-ch
fmt.Println(v2, ok2) // "" false — channel closed
}L'invio su un canale chiuso causa un panic
L'invio a un canale chiuso causa un panic. Solo il mittente dovrebbe chiudere un canale: mai il ricevitore:
package main
import "fmt"
func main() {
ch := make(chan int)
close(ch)
// Receiving from closed channel returns zero value
v, ok := <-ch
fmt.Println(v, ok) // 0 false
// Sending to closed channel panics:
defer func() { recover() }()
ch <- 1 // panic: send on closed channel
}Canali unidirezionali
Limiti i canali alla sola trasmissione (chan<- T) o alla sola ricezione (<-chan T) nelle firme delle funzioni, per maggiore chiarezza e sicurezza:
package main
import "fmt"
func producer(out chan<- int) { // send-only
for i := 0; i < 3; i++ { out <- i }
close(out)
}
func consumer(in <-chan int) { // receive-only
for v := range in { fmt.Println(v) }
}
func main() {
ch := make(chan int)
go producer(ch)
consumer(ch)
}Ping-pong tra goroutine e canali
Due goroutine si scambiano un messaggio tramite i canali: una classica dimostrazione della sincronizzazione:
package main
import "fmt"
func ping(ping, pong chan struct{}) {
for i := 0; i < 3; i++ {
<-ping
fmt.Println("ping")
pong <- struct{}{}
}
}
func main() {
ping := make(chan struct{})
pong := make(chan struct{})
go func() { for { <-pong; fmt.Println("pong"); ping <- struct{}{} } }()
go func() { for i := 0; i < 3; i++ { ping <- struct{}{}; <-pong } }()
// Simplified version:
fmt.Println("channels enable structured communication")
}I canali nil si bloccano per sempre
La ricezione da un canale nil o l'invio a tale canale si blocca per sempre. Questo comportamento viene talvolta utilizzato intenzionalmente nelle istruzioni select:
package main
import "fmt"
func main() {
var ch chan int // nil channel
fmt.Println(ch == nil) // true
// select with nil channel — that case is never selected
active := make(chan int, 1)
active <- 42
select {
case v := <-ch: // never selected (nil)
fmt.Println(v)
case v := <-active: // selected
fmt.Println("got:", v)
}
}Quando utilizzare i canali senza buffer
Utilizzi i canali senza buffer quando:
- È necessario un passaggio sincrono garantito
- La goroutine deve confermare la ricezione prima che il mittente prosegua
- Implementa semafori o il controllo del flusso (backpressure)
- Implementa pipeline in cui ogni fase deve elaborare un elemento alla volta
Verifica rapida
Che cosa accade quando si invia su un canale senza buffer senza alcun ricevitore pronto?
Riepilogo: canali senza buffer
Riepilogo:
- Crei con
make(chan T): capacità zero - L'invio si blocca finché il ricevitore non è pronto; la ricezione si blocca finché il mittente non invia
- Solo il mittente dovrebbe chiudere un canale
range chesegue l'iterazione fino alla chiusura- Ricezione a due valori:
v, ok := <-ch - Utilizzi tipi unidirezionali per maggiore chiarezza:
chan<-e<-chan
Domande Frequenti
La lezione «Canali non bufferizzati» è gratuita?
Sì — il testo completo di «Canali non bufferizzati» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Go Academy, passa a CoddyKit PRO. Il corso Go Academy include 4 lezioni in totale.
Cosa imparerò in «Canali non bufferizzati»?
Passaggio sincrono tra goroutine Eserciti Go Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Go Academy?
Non è richiesta alcuna esperienza precedente. Go Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.
Quanto tempo richiede la lezione «Canali non bufferizzati»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Go Academy?
Sì. Ogni lezione Go Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Avviare goroutine
- Canali non bufferizzati
- Canali bufferizzati
- Direzione dei canali e modelli pipeline