Maison > développement back-end > Golang > Pourquoi ce code Go imprime-t-il « Trois » trois fois au lieu de « Un », « Deux » et « Trois » ?

Pourquoi ce code Go imprime-t-il « Trois » trois fois au lieu de « Un », « Deux » et « Trois » ?

DDD
Libérer: 2024-12-09 13:41:11
original
1024 Les gens l'ont consulté

Why Does This Go Code Print

Comportement de Goroutine : résoudre le mystère

Nous tombons sur un comportement déroutant dans le code Go fourni :

package main

import (
    "fmt"
    "time"
)

type field struct {
    name string
}

func (p *field) print() {
    fmt.Println(p.name)
}

func main() {
    data := []field{{"one"}, {"two"}, {"three"}}
    for _, v := range data {
        go v.print()
    }
    <-time.After(1 * time.Second)
}
Copier après la connexion

La question se pose : pourquoi ce code imprime-t-il systématiquement "trois" trois fois, au lieu d'afficher "un", "deux" et "trois" dans n'importe quel ordre ?

Comprendre le problème

Le nœud du problème réside dans une subtile condition de concurrence provoquée par l'utilisation de la variable de plage v dans la fonction goroutine.

Lorsque nous écrivons v.print(), nous passons effectivement un pointeur vers la variable v, qui est une référence à l'élément actuel dans la boucle de données de plage. Cependant, la boucle continue d'itérer, modifiant la valeur de v.

Lorsque la goroutine s'exécute, elle a la valeur finale de v, qui est "trois". Cela produit le résultat inattendu de trois « trois ».

Résoudre le problème : approches multiples

Il existe plusieurs façons de résoudre ce problème :

1. Utilisation d'une déclaration de variable courte :

Créez une nouvelle variable v limitée à chaque itération de la boucle :

for _, v := range data {
    v := v // Short variable declaration to create a new `v`.
    go v.print()
}
Copier après la connexion

2. Utilisation d'une tranche de pointeurs :

Changez le type de données en une tranche de pointeurs et transmettez les pointeurs individuels à la fonction goroutine :

data := []*field{{"one"}, {"two"}, {"three"}} // Note the '*'
for _, v := range data {
    go v.print()
}
Copier après la connexion

3. Utilisation de l'adresse de l'élément Slice :

Prenez l'adresse de chaque élément slice et passez le pointeur vers la fonction goroutine :

data := []*field{{"one"}, {"two"}, {"three"}} // Note the '*'
for i := range data {
    v := &data[i]
    go v.print()
}
Copier après la connexion

Conclusion

N'oubliez pas que prendre des adresses de variables de plage peut entraîner un comportement inattendu dans les goroutines si la boucle modifie la valeur des variables. En utilisant les techniques décrites ci-dessus, nous pouvons garantir que chaque goroutine reçoit une valeur unique et éviter les problèmes de course aux données.

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!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal