追加函數:同時存取不是執行緒安全的
在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中文網其他相關文章!