"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Pourquoi la fonction « append » n'est-elle pas thread-safe pour un accès simultané dans Go ?

Pourquoi la fonction « append » n'est-elle pas thread-safe pour un accès simultané dans Go ?

Publié le 2024-11-11
Parcourir:870

Why is `append` function not thread-safe for concurrent access in Go?

Fonction d'ajout : non thread-safe pour l'accès simultané

Lors de l'utilisation simultanée de goroutines pour ajouter des éléments à une tranche dans une boucle for, des anomalies dans les données peut survenir. Des données manquantes ou vides peuvent apparaître dans la tranche résultante, indiquant des courses de données potentielles.

Cela se produit car dans Go, aucune valeur n'est intrinsèquement sûre pour la lecture et l'écriture simultanées. Les tranches, représentées par des en-têtes de tranche, ne font pas exception. Le code fourni présente des courses de données dues à un accès simultané :

destSlice := make([]myClass, 0)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        destSlice = append(destSlice, tmpObj)
    }(myObject)
}
wg.Wait()

Pour vérifier la présence de courses de données, exécutez la commande suivante :

go run -race play.go

La sortie vous alertera des données courses :

WARNING: DATA RACE
...

Résolution des problèmes de concurrence

Pour résoudre ce problème, protégez l'accès en écriture à destSlice en utilisant un sync.Mutex :

var (
    mu        = &sync.Mutex{}
    destSlice = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        mu.Lock()
        destSlice = append(destSlice, tmpObj)
        mu.Unlock()
    }(myObject)
}
wg.Wait()

Vous pouvez également envisager d'utiliser un canal pour gérer de manière asynchrone les ajouts :

var (
    appendChan = make(chan myClass)
    destSlice  = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        appendChan 
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3