Heim  >  Artikel  >  Backend-Entwicklung  >  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?

Patricia Arquette
Patricia ArquetteOriginal
2024-11-10 03:50:02336Durchsuche

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

Anhängefunktion: Nicht Thread-sicher für gleichzeitigen Zugriff

Bei der gleichzeitigen Verwendung von Goroutinen zum Anhängen von Elementen an ein Slice innerhalb einer for-Schleife treten Anomalien auf in Daten entstehen können. Fehlende oder leere Daten können im resultierenden Slice 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 Datenrennen aufmerksam :

WARNING: DATA RACE
...

Parallelitätsprobleme lösen

An Um dieses Problem zu beheben, schützen Sie den Schreibzugriff auf das destSlice, indem Sie einen sync.Mutex verwenden:

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 einen Kanal verwenden, um die Anhänge asynchron zu verarbeiten:

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

Das obige ist der detaillierte Inhalt vonWarum ist die Funktion „Anhängen' für den gleichzeitigen Zugriff in Go nicht threadsicher?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn