0Pricing
Go Academy · Lezione

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 ch esegue 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

  1. Avviare goroutine
  2. Canali non bufferizzati
  3. Canali bufferizzati
  4. Direzione dei canali e modelli pipeline
← Torna a Go Academy