Maison >développement back-end >Golang >Pourquoi l'ajout aux tranches dans Go est-il dangereux pour les threads ?

Pourquoi l'ajout aux tranches dans Go est-il dangereux pour les threads ?

Susan Sarandon
Susan Sarandonoriginal
2024-11-09 17:30:02319parcourir

Why is appending to slices in Go thread-unsafe?

Pourquoi l'ajout à des tranches peut être dangereux pour les threads

Lorsque plusieurs goroutines tentent d'ajouter des données à une tranche simultanément, une condition de concurrence critique entre les données peut se produire. En effet, les tranches dans Go ne sont pas thread-safe, ce qui signifie que plusieurs goroutines peuvent accéder et modifier simultanément le même en-tête de tranche, ce qui peut potentiellement provoquer une corruption des données.

Illustration de la course aux données

Considérez le code suivant :

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()

Dans ce code, plusieurs goroutines s'ajoutent simultanément à la tranche destSlice. Cela peut entraîner des données manquantes ou vides dans la tranche résultante, car les goroutines peuvent entrelacer leurs opérations et écraser les modifications les unes des autres.

Vérification des courses de données avec l'option "-race"

L'exécution du code avec l'option "-race" générera un avertissement pour chaque course aux données détectée. Le résultat suivant illustre les conditions de concurrence des données dans le code fourni :

==================
WARNING: DATA RACE
Read at 0x00c420074000 by goroutine 6:
  main.main.func1()
      /home/icza/gows/src/play/play.go:20 +0x69

Previous write at 0x00c420074000 by goroutine 5:
  main.main.func1()
      /home/icza/gows/src/play/play.go:20 +0x106

Goroutine 6 (running) created at:
  main.main()
      /home/icza/gows/src/play/play.go:21 +0x1cb

Goroutine 5 (running) created at:
  main.main()
      /home/icza/gows/src/play/play.go:21 +0x1cb
==================

Solution : Utilisation d'un mutex pour la synchronisation

Pour garantir des ajouts simultanés sécurisés par les threads, vous peut utiliser un mutex pour protéger l'en-tête de la tranche destSlice. Le code modifié suivant le démontre :

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()

En acquérant le mutex avant chaque opération d'ajout, vous empêchez plusieurs goroutines de modifier simultanément l'en-tête de tranche, garantissant l'intégrité des données et éliminant la condition de concurrence critique des 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!

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