Passer au contenu principal
eLearner.app
Module 7 · Leçon 1 sur 531/50 dans le cours~12 min
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
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

Go
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 :

Go
// 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 propagati

Le bug "classique" de fermeture en boucle

Jusqu'à Go 1.21, c'était un problème fréquent :

Go
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 :

Go
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

AspectsGoroutineFil de discussion du système d'exploitation
Pile initiale~2 Ko1 à 8 Mo (alloué au démarrage)
Créationnanosecondesmicrosecondes
PlanificationPasser au runtime (coopératif)noyau (préemptif)
Compte pratique100 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

Exercice#go.m7.l1.e1
Tentatives : 0Chargement…

Lancez la fonction d'accueil en tant que goroutine et attendez 100 ms avec le temps. Dormez avant de quitter le principal.

Chargement de l'éditeur…
Afficher l'indice

`go` devant un appel de fonction lance la goroutine.

Solution disponible après 3 tentatives

Exercice#go.m7.l1.e2
Tentatives : 0Chargement…

Lancez une fonction anonyme en tant que goroutine qui imprime « salut ».

Chargement de l'éditeur…
Afficher l'indice

Une fonction anonyme est appelée avec un `()` final : `go func(){...}()`.

Solution disponible après 3 tentatives

Quiz#go.m7.l1.e3
Prêt

Que se passe-t-il si `main` se termine avant la fin d'une goroutine ?

Go
func main() {
  go work()
  // main ritorna immediatamente
}
Options de réponse

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.
  • main n'attend pas : il faut une synchronisation (canal/WaitGroup/context).
  • time.Sleep est uniquement didactique, jamais de synchronisation en production.
  • Depuis Go 1.22 la variable for est "fraîche" à chaque itération (plus de bug "3 3 3").