追加函數:並發存取不是線程安全的
當同時使用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