Maison > Article > développement back-end > Pourquoi l'ajout à une tranche dans des goroutines simultanées n'est-il pas thread-safe ?
Tranches simultanées : ajout non thread-safe
Question :
Considérez le code suivant qui s'ajoute à une tranche à l'aide de plusieurs goroutines dans une boucle for :
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()
À l'occasion, ce code produit des données manquantes ou vides dans destSlice ou n'inclut pas tous les éléments de sourceSlice. Pourquoi cela pourrait-il se produire ?
Réponse :
Dans Go, toutes les valeurs sont sensibles aux courses de données lorsqu'elles sont soumises à des opérations de lecture/écriture simultanées, y compris les tranches. Cela est dû à la façon dont les en-têtes de tranche (qui contiennent les informations sur la capacité et la longueur de la tranche) sont implémentés.
L'exécution du code avec l'indicateur -race confirmera la présence de courses de données :
go run -race play.go
Solution :
Pour éviter les courses de données et garantir la sécurité simultanée lors de l'ajout à une tranche, une primitive de synchronisation telle qu'un sync.Mutex doit être utilisée pour protéger le écriture de la valeur destSlice :
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 des canaux pour faciliter le processus d'ajout simultané.
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!