Storia della domanda:
La goroutine leak è una situazione in cui una goroutine continua a esistere e rimane in memoria, anche se ha "perso il senso" (i calcoli sono stati completati, i dati non sono necessari, ma non c'è una condizione di uscita). Simile alle perdite di memoria, ma per i thread di esecuzione. Questo è critico per Go: un carico elevato può portare all'esaurimento delle risorse.
Problema:
A differenza di altri linguaggi, dove il controllo diretto dei thread spesso porta alla loro chiusura manuale, in Go le goroutine vengono avviate facilmente, ma non sempre si completano correttamente. Un errore comune: la logica principale è terminata, mentre la goroutine è "bloccata" — aspetta dati su un canale chiuso o non riceverà mai un segnale.
Soluzione:
Per prevenire le perdite si usano strutture di controllo: context, chiusura dei canali, variabili di segnale. È importante progettare preventivamente i percorsi di uscita da ogni goroutine, utilizzare defer per la pulizia. Esempio:
func worker(ctx context.Context, jobs <-chan int, results chan<- int) { for { select { case <-ctx.Done(): return case job, ok := <-jobs: if !ok { return } results <- job * 2 } } }
Caratteristiche chiave:
È possibile chiudere semplicemente il canale per fermare la goroutine?
Non sempre. Se nel select ci sono altri case o non c'è un controllo della chiusura tramite ok, la goroutine potrebbe rimanere "bloccata".
val, ok := <-ch if !ok { return } // Questo è più corretto
Cosa succede se si dimentica di gestire context.Done nel select?
La goroutine non saprà mai che l'annullamento è avvenuto — rimarrà "eterna". Questo è un percorso diretto verso una leak.
È possibile individuare una leak usando il runtime di Go?
Non esiste uno strumento standard per il monitoraggio delle leak. È necessario monitorare il numero di goroutine attive tramite runtime.NumGoroutine o utilizzare rilevatori di leak di librerie di terze parti.
Nel sistema di invio push vengono avviate goroutine per ogni messaggio in entrata, ma si dimenticano di fermarle quando il contesto viene annullato o il canale chiuso — centinaia di goroutine "morte" rimangono in memoria.
Pro:
Contro:
Il funzionamento della goroutine è controllato tramite il contesto, a livello di logica di business viene verificata l'uscita dal select, dopo l'invio/elaborazione riuscita il canale viene chiuso.
Pro:
Contro: