Comment terminer correctement l'exécution de plusieurs goroutines en Go?
sobes.tech IA
Réponse de l'IA
Il existe plusieurs méthodes courantes :
-
Utilisation du contexte (Context) : Approche recommandée pour annuler des opérations dans une structure arborescente d'appels. Le contexte peut transmettre un signal d'annulation via un canal.
package main import ( "context" "fmt" "time" ) func worker(ctx context.Context, id int) { for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d se termine : %v\n", id, ctx.Err()) return default: fmt.Printf("Goroutine %d en cours d'exécution...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) go worker(ctx, 1) go worker(ctx, 2) time.Sleep(3 * time.Second) cancel() // Envoi du signal d'annulation time.Sleep(1 * time.Second) // Attente de la terminaison des goroutines fmt.Println("Programme principal terminé.") } -
Utilisation de canaux : En envoyant un signal (par exemple, une structure vide
struct{}) via un canal spécial, on peut informer la goroutine qu'elle doit se terminer.package main import ( "fmt" "time" ) func worker(stopChan <-chan struct{}, id int) { for { select { case <-stopChan: fmt.Printf("Goroutine %d se termine via canal\n", id) return default: fmt.Printf("Goroutine %d en cours d'exécution...\n", id) time.Sleep(1 * time.Second) } } } func main() { stopChan := make(chan struct{}) go worker(stopChan, 1) go worker(stopChan, 2) time.Sleep(3 * time.Second) close(stopChan) // La fermeture du canal indique la fin time.Sleep(1 * time.Second) // Attente de la terminaison des goroutines fmt.Println("Programme principal terminé.") } -
Utilisation de
sync.WaitGroup(pour attendre la fin, pas pour signaler) :WaitGroupest utilisé pour attendre la fin d'un groupe de goroutines, mais ne fournit pas de mécanisme d'arrêt en soi. Il est souvent combiné avec un contexte ou des canaux.package main import ( "context" "fmt" "sync" "time" ) func worker(ctx context.Context, wg *sync.WaitGroup, id int) { defer wg.Done() // Décrémente le compteur du WaitGroup à la fin for { select { case <-ctx.Done(): fmt.Printf("Goroutine %d se termine\n", id) return default: fmt.Printf("Goroutine %d en cours d'exécution...\n", id) time.Sleep(1 * time.Second) } } } func main() { ctx, cancel := context.WithCancel(context.Background()) var wg sync.WaitGroup numWorkers := 2 wg.Add(numWorkers) // Initialisation du WaitGroup for i := 1; i <= numWorkers; i++ { go worker(ctx, &wg, i) } time.Sleep(3 * time.Second) cancel() // Signal d'annulation wg.Wait() // Attente de la fin de toutes les goroutines fmt.Println("Programme principal terminé.") }
Le choix de la méthode dépend du cas d'utilisation spécifique et de la complexité des interactions entre goroutines. Le contexte est généralement préféré pour les annulations en cascade.