」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 為什麼 Go 中的「append」函數對於並發存取不是線程安全的?

為什麼 Go 中的「append」函數對於並發存取不是線程安全的?

發佈於2024-11-11
瀏覽:854

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

追加函數:並發存取不是線程安全的

當同時使用goroutine 將元素追加到for 循環中的切片時,出現異常數據中可能會出現。結果切片中可能會出現遺失或空白數據,表示潛在的數據競爭。

發生這種情況是因為在 Go 中,沒有值對於同時讀寫來說是天生安全的。由切片頭表示的切片也不例外。提供的程式碼因並發存取而出現資料爭用:

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

要驗證資料競爭是否存在,請執行以下指令:

go run -race play.go

輸出將提醒您資料競賽競賽:

WARNING: DATA RACE
...

解決並發問題

要解決此問題,請使用sync.Mutex 保護對 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()

或者,考慮使用通道非同步處理追加:

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 
最新教學 更多>

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3