Gleichzeitige Slices: Anhängen nicht threadsicher
Frage:
Bedenken Sie den folgenden Code das an ein Slice angehängt wird und mehrere Goroutinen innerhalb eines for verwendet Schleife:
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()
Gelegentlich erzeugt dieser Code fehlende oder leere Daten in destSlice oder schließt nicht alle Elemente aus sourceSlice ein. Warum könnte das passieren?
Antwort:
In Go sind alle Werte anfällig für Datenwettläufe, wenn sie gleichzeitigen Lese-/Schreibvorgängen unterliegen, einschließlich Slices. Dies liegt an der Art und Weise, wie Slice-Header (die Informationen über die Kapazität und Länge des Slice enthalten) implementiert werden.
Das Ausführen des Codes mit der Flagge -race bestätigt das Vorhandensein von Datenrennen:
go run -race play.go
Lösung:
Um Datenwettläufe zu vermeiden und gleichzeitige Sicherheit beim Anhängen an einen Slice zu gewährleisten, ein Synchronisationsprimitiv B. ein sync.Mutex, sollte verwendet werden, um das Schreiben des destSlice-Werts zu schützen:
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()
Alternativ können Sie Kanäle verwenden, um den gleichzeitigen Anhängeprozess zu erleichtern.
Das obige ist der detaillierte Inhalt vonWarum ist das Anhängen an ein Slice in gleichzeitigen Goroutinen nicht threadsicher?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!