Comprendre le comportement curieux des Goroutines dans un scénario de course aux données
Dans le code Go fourni, nous créons une tranche de champs de structure appelée données contenant les noms « un », « deux » et « trois ». Le code parcourt la tranche, créant des goroutines pour imprimer le nom de chaque champ à l'aide de la méthode d'impression. Cependant, contrairement aux attentes, le code imprime à plusieurs reprises « trois » trois fois, plutôt que la séquence prévue de « un », « deux » et « trois ».
Dévoilement de la course aux données
Ce comportement curieux découle d'une course aux données, qui se produit lorsque plusieurs goroutines accèdent et modifient potentiellement les mêmes données partagées simultanément. Dans ce cas, le problème vient de l’utilisation implicite de l’adresse de la variable range v lors de la création des goroutines. Lorsque la variable de boucle v est modifiée à chaque itération, les goroutines finissent par utiliser sa valeur finale, ce qui entraîne l'impression constante de « trois ».
Répondre à la course aux données
Pour résoudre ce problème, nous pouvons adopter plusieurs approches :
Créer une nouvelle variable dans chaque boucle Itération : Dans la boucle, nous pouvons déclarer une nouvelle variable avec le même nom que la variable de plage, créant ainsi une nouvelle portée pour la variable.
for _, v := range data { v := v // Declare a new variable `v` within the loop scope. go v.print() }
Utiliser une tranche de pointeurs : Au lieu d'utiliser une tranche de champs de structure, nous pouvons utiliser une tranche de pointeurs vers les champs. Cela garantit que les goroutines reçoivent des pointeurs vers des éléments de champ individuels, évitant ainsi les problèmes de course aux données.
data := []*field{ {"one"},{"two"},{"three"} } for _, v := range data { go v.print() }
Transmission de l'adresse de l'élément Slice : Une autre alternative consiste à transmettre l'adresse de chaque élément de la tranche au goroutine.
for i := range data { v := &data[i] // Take the address of the slice element. go v.print() }
Utilisation de fonctions anonymes et transmission de variables de plage comme arguments : Si la fonction goroutine se trouve dans une fonction anonyme, nous pouvons éviter le problème en passant les variables de plage comme arguments de la fonction.
for _, v := range data { go func(v field) { // Pass the range variable `v` as an argument. v.print() }(v) }
Ces approches garantissent que les goroutines ont leurs propres copies des données dont elles ont besoin, éliminant ainsi la course aux données et produisant la sortie correcte de « un », « deux » et « trois » dans n'importe quel ordre.
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!