Maison >développement back-end >Golang >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 ?

Patricia Arquette
Patricia Arquetteoriginal
2024-11-10 03:50:02365parcourir

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

Fonction d'ajout : non thread-safe pour un 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 courses de données :

WARNING: DATA RACE
...

Résoudre les problèmes de concurrence

Pour résoudre ce problème, protégez l'accès en écriture au 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 les ajouts de manière asynchrone :

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 <- tmpObj
    }(myObject)
}
go func() {
    for {
        tmpObj := <-appendChan
        destSlice = append(destSlice, tmpObj)
    }
}()
wg.Wait()

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!

Déclaration:
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