Meilleures pratiques pour utiliser sync.WaitGroup avec des fonctions externes
Pour gérer la concurrence dans Go, il est crucial d'utiliser efficacement sync.WaitGroup. Cet article aborde un problème courant qui survient lors du passage d'un groupe d'attente comme argument à une fonction externe.
Problème :
Considérez le code suivant :
<code class="go">package main import ( "fmt" "sync" ) func main() { ch := make(chan int) var wg sync.WaitGroup wg.Add(2) go Print(ch, wg) // go func(){ for i := 1; i <= 11; i++ { ch <- i } close(ch) defer wg.Done() }() wg.Wait() //deadlock here } // Print prints all numbers sent on the channel. // The function returns when the channel is closed. func Print(ch <-chan int, wg sync.WaitGroup) { for n := range ch { // reads from channel until it's closed fmt.Println(n) } defer wg.Done() }</code>
Dans ce code, un blocage se produit au niveau de la ligne spécifiée, obligeant le programme à imprimer uniquement de 1 à 10 au lieu d'atteindre 11. L'erreur provient du passage d'une copie de sync.WaitGroup à la méthode Print, ce qui gêne l'appel attendu à sa méthode Done.
Solution 1 :
Pour résoudre ce problème, passez plutôt un pointeur vers le groupe d'attente :
<code class="go">package main import ( "fmt" "sync" ) func main() { ch := make(chan int) var wg sync.WaitGroup wg.Add(2) go Print(ch, &wg) go func() { for i := 1; i <= 11; i++ { ch <- i } close(ch) defer wg.Done() }() wg.Wait() //deadlock here } func Print(ch <-chan int, wg *sync.WaitGroup) { for n := range ch { // reads from channel until it's closed fmt.Println(n) } defer wg.Done() }</code>
Transmettre l'adresse de wg garantit que la méthode Print appelle la méthode Done sur le groupe d'attente qui est attendu dans la fonction principale.
Solution 2 : Méthode d'impression simplifiée
Alternativement, la méthode Print peut être simplifiée en supprimant l'argument WaitGroup, car elle ne nécessite la connaissance d'aucune opération d'attente :
<code class="go">package main import ( "fmt" ) func main() { ch := make(chan int) go func() { for i := 1; i <= 11; i++ { ch <- i } close(ch) }() for n := range ch { // reads from channel until it's closed fmt.Println(n) } } </code>
Dans ce scénario, la goroutine principale reçoit directement le canal et imprime ses valeurs sans impliquer un groupe d'attente. Cette approche maintient la fonctionnalité souhaitée et élimine le besoin de gestion WaitGroup au sein de la méthode Print.
Conclusion :
Lors du passage de sync.WaitGroup comme argument à des fonctions externes, il est essentiel de s'assurer que la fonction reçoit la bonne référence au groupe d'attente attendu. Refactoriser la fonction pour gérer directement les groupes d'attente ou passer un pointeur vers le groupe d'attente peut efficacement éviter les erreurs de blocage et garantir un contrôle de concurrence approprié.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!