首頁 > 後端開發 > Golang > 主體

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

Patricia Arquette
發布: 2024-11-10 03:50:02
原創
331 人瀏覽過

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

追加函數:同時存取不是執行緒安全的

在for 迴圈中並發使用goroutine 向切片追加元素時,出現異常資料中可能會出現。結果切片中可能會出現遺失或空白數據,這表明存在潛在的數據競爭。

發生這種情況是因為在 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 <- tmpObj
    }(myObject)
}
go func() {
    for {
        tmpObj := <-appendChan
        destSlice = append(destSlice, tmpObj)
    }
}()
wg.Wait()
登入後複製

以上是為什麼 Go 中的「append」函數對於並發存取不是線程安全的?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板