Leçons du module (1/5)
Goroutines : parallélisme léger
Une goroutine est une unité d'exécution concurrente gérée par le Go
exécution. Vous en lancez un avec le mot clé go devant une fonction
appeler :
go greet("Anna") // chiamata a funzione esistente
go func() { // funzione anonima
fmt.Println("hi")
}()L'instruction go renvoie immédiatement : la goroutine démarre dans
parallèle et l'appelant continue.
Pourquoi ils sont "légers"
- Pile initiale ~2 Ko (croît dynamiquement, jusqu'à des centaines de Mo si nécessaire).
- Multiplexé sur un petit nombre de threads du système d'exploitation par le runtime (
GOMAXPROCS). - Des milliers/millions de goroutines sont routinières ; avec les threads du système d'exploitation, cela serait impossible.
Conceptuellement, il s'agit de « tirer et oublier simultanément », mais avec tous les
outils idiomatiques pour coordonner (canaux, sync.WaitGroup,
context).
main n'attend pas
func main() {
go func() { fmt.Println("ciao dalla goroutine") }()
// main esce subito: niente garanzia che la goroutine completi
}Lorsque main revient, le processus se termine : les goroutines ne reçoivent pas
pour « finir leur travail », ils sont simplement tués avec les
processus. Une synchronisation explicite est requise.
Synchronisation : un aperçu
Les trois outils que vous verrez dans les prochaines leçons :
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
work()
done <- struct{}{}
}()
<-done // attendi
// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()
// 3) context: cancellazione/timeout propagatiLe bug "classique" de fermeture en boucle
Jusqu'à Go 1.21, c'était un problème fréquent :
for i := 0; i < 3; i++ {
go func() { fmt.Println(i) }() // stampa "3 3 3" su versioni vecchie
}Depuis Go 1.22, la variable for est fraîchement créée sur chaque
itération, donc le bug est corrigé par défaut. Dans les anciennes bases de code, vous
voyez toujours le modèle de correctif :
for i := 0; i < 3; i++ {
i := i // shadow esplicito
go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
go func(n int) { fmt.Println(n) }(i)
}Goroutine != Fil de discussion du système d'exploitation
| Aspects | Goroutine | Fil de discussion du système d'exploitation |
|---|---|---|
| Pile initiale | ~2 Ko | 1 à 8 Mo (alloué au démarrage) |
| Création | nanosecondes | microsecondes |
| Planification | Passer au runtime (coopératif) | noyau (préemptif) |
| Compte pratique | 100 000+ | quelques milliers |
Un seul thread du système d’exploitation peut héberger plusieurs goroutines. Le runtime se déplace des goroutines sur les threads en cas de besoin.
Essayez-le
Lancez la fonction d'accueil en tant que goroutine et attendez 100 ms avec le temps. Dormez avant de quitter le principal.
Afficher l'indice
`go` devant un appel de fonction lance la goroutine.
Solution disponible après 3 tentatives
Lancez une fonction anonyme en tant que goroutine qui imprime « salut ».
Afficher l'indice
Une fonction anonyme est appelée avec un `()` final : `go func(){...}()`.
Solution disponible après 3 tentatives
Que se passe-t-il si `main` se termine avant la fin d'une goroutine ?
func main() {
go work()
// main ritorna immediatamente
}Récapitulatif
go f()lance f() simultanément ; il revient immédiatement.- Goroutine = ~2 Ko initial, multiplexé sur quelques threads du système d'exploitation.
mainn'attend pas : il faut une synchronisation (canal/WaitGroup/context).time.Sleepest uniquement didactique, jamais de synchronisation en production.- Depuis Go 1.22 la variable
forest "fraîche" à chaque itération (plus de bug "3 3 3").