Maison > développement back-end > Golang > le corps du texte

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

Patricia Arquette
Libérer: 2024-11-10 03:50:02
original
336 Les gens l'ont consulté

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()
Copier après la connexion

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

go run -race play.go
Copier après la connexion

La sortie vous alertera des courses de données :

WARNING: DATA RACE
...
Copier après la connexion

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()
Copier après la connexion

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()
Copier après la connexion

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
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal