0Pricing
Go Academy · Lezione

Avviare goroutine

La parola chiave go, il ciclo di vita delle goroutine e i WaitGroup

Avviare goroutine è una lezione Go Academy gratuita su CoddyKit. Questa è la lezione 1 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'è una goroutine?

Una goroutine è una funzione leggera eseguita in concorrenza e gestita dal runtime di Go. Le goroutine sono molto meno costose dei thread del sistema operativo: è possibile eseguirne migliaia:

  • Avvio con la parola chiave go
  • Stack iniziale di circa 2 KB, che cresce dinamicamente
  • Pianificate dal runtime di Go, non dal sistema operativo
  • Comunicazione tramite canali, non tramite memoria condivisa

La parola chiave go

Preceda qualsiasi chiamata di funzione con go per avviarla come goroutine:

package main
import ("fmt"; "time")

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    go greet("Alice")   // runs concurrently
    go greet("Bob")     // runs concurrently
    time.Sleep(100 * time.Millisecond) // wait for goroutines
    fmt.Println("done")
}

Ciclo di vita di una goroutine

Una goroutine inizia quando viene eseguita l'istruzione go e termina quando la sua funzione restituisce il controllo. Se main termina, tutte le goroutine vengono terminate:

package main
import ("fmt"; "time")

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Duration(id) * 50 * time.Millisecond)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }
    time.Sleep(300 * time.Millisecond) // naive wait
}

sync.WaitGroup per il coordinamento

Utilizzi sync.WaitGroup invece di sleep per attendere il completamento delle goroutine:

package main
import ("fmt"; "sync")

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // signal completion
    fmt.Printf("Worker %d working\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
        wg.Add(1)           // register one goroutine
        go worker(i, &wg)
    }
    wg.Wait()               // block until all Done()
    fmt.Println("all workers finished")
}

Goroutine anonime

Avvii direttamente una funzione anonima come goroutine: è utile per le attività concorrenti definite inline:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        i := i  // capture loop variable
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Printf("goroutine %d\n", i)
        }()
    }
    wg.Wait()
}

Problema della cattura della variabile del ciclo

Se non catturate la variabile del ciclo, tutte le goroutine potrebbero vedere lo stesso valore finale: un classico bug di concorrenza in Go:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(n int) {  // pass i as argument — safe
            defer wg.Done()
            fmt.Println(n)  // prints 0, 1, 2 in some order
        }(i)
    }
    wg.Wait()
}

Goroutine e thread

Perché le goroutine sono preferibili ai thread del sistema operativo:

  • Stack iniziale di 2 KB contro circa 1 MB per i thread del sistema operativo
  • La creazione richiede microsecondi invece di millisecondi
  • Il runtime di Go distribuisce le goroutine sui thread del sistema operativo indicati da GOMAXPROCS
  • I cambi di contesto tra goroutine sono cooperativi: non coinvolgono il kernel
  • Go gestisce la pianificazione, mentre Lei si concentra sulla logica

GOMAXPROCS

runtime.GOMAXPROCS controlla quanti thread del sistema operativo eseguono goroutine in parallelo; per impostazione predefinita corrisponde al numero di CPU:

package main
import ("fmt"; "runtime")

func main() {
    // Default: number of available CPU cores
    fmt.Println("CPUs:", runtime.NumCPU())
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // 0 = query without changing

    // Set to 1 for debugging race conditions:
    // runtime.GOMAXPROCS(1)

    fmt.Println("Goroutines:", runtime.NumGoroutine())
}

Perdite di goroutine

Si verifica una perdita di goroutine quando una goroutine viene avviata ma non termina mai. Cause comuni: ricezione bloccata su un canale, mutex bloccato o assenza di annullamento:

package main
import ("fmt"; "time"; "runtime")

func leaky() {
    ch := make(chan int)  // nobody sends to ch
    go func() {
        v := <-ch  // blocks forever — goroutine leaked!
        fmt.Println(v)
    }()
}

func main() {
    leaky()
    time.Sleep(10 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // > 1
}

Buone pratiche per le goroutine

Linee guida per le goroutine:

  • Sappia sempre come terminerà una goroutine
  • Utilizzi WaitGroup o i canali per la sincronizzazione, non sleep
  • Passi le variabili del ciclo come argomenti di funzione, non tramite una closure
  • Annulli le goroutine con il contesto, senza lasciarle in esecuzione
  • Utilizzi il race detector: go run -race main.go

Verifica rapida

Qual è il modo corretto per evitare il bug della cattura della variabile del ciclo nelle goroutine?

Riepilogo: avvio delle goroutine

Riepilogo:

  • Avvii con go fn(): è leggero ed economico
  • Utilizzi sync.WaitGroup per attendere: Add(1), defer Done(), Wait()
  • Catturi le variabili del ciclo tramite un argomento o una nuova dichiarazione
  • Sappia sempre come termina ogni goroutine, così da prevenire le perdite
  • Utilizzi il flag -race per rilevare le race condition sui dati

Domande Frequenti

La lezione «Avviare goroutine» è gratuita?

Sì — il testo completo di «Avviare goroutine» è 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 «Avviare goroutine»?

La parola chiave go, il ciclo di vita delle goroutine e i WaitGroup 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 1 di 4.

Quanto tempo richiede la lezione «Avviare goroutine»?

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