„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Warum ist die Funktion „Anhängen“ für den gleichzeitigen Zugriff in Go nicht threadsicher?

Warum ist die Funktion „Anhängen“ für den gleichzeitigen Zugriff in Go nicht threadsicher?

Veröffentlicht am 11.11.2024
Durchsuche:581

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

Append-Funktion: Nicht Thread-sicher für gleichzeitigen Zugriff

Bei der gleichzeitigen Verwendung von Goroutinen zum Anhängen von Elementen an einen Slice innerhalb einer for-Schleife treten Anomalien auf in Daten entstehen können. Im resultierenden Slice können fehlende oder leere Daten erscheinen, was auf mögliche Datenrennen hinweist.

Dies liegt daran, dass in Go kein Wert von Natur aus sicher für gleichzeitiges Lesen und Schreiben ist. Slices, die durch Slice-Header dargestellt werden, bilden keine Ausnahme. Der bereitgestellte Code weist Datenrennen aufgrund des gleichzeitigen Zugriffs auf:

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

Um das Vorhandensein von Datenrennen zu überprüfen, führen Sie den folgenden Befehl aus:

go run -race play.go

Die Ausgabe macht Sie auf Daten aufmerksam Rennen:

WARNING: DATA RACE
...

Lösen von Parallelitätsproblemen

Um dieses Problem zu beheben, schützen Sie den Schreibzugriff auf das destSlice durch den Einsatz eines 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()

Erwägen Sie alternativ die Verwendung eines Kanals zur asynchronen Verarbeitung der Anhänge:

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 
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3