為什麼追加到切片可能是線程不安全的
當多個goroutine 嘗試同時將資料追加到切片時,資料競爭條件可能會發生發生。這是因為 Go 中的切片不是線程安全的,這意味著多個 goroutine 可以同時存取和修改同一個切片頭,這可能會導致資料損壞。
資料爭用說明
考慮以下程式碼:
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()
在此程式碼中,多個 goroutine 同時附加到 destSlice 切片。這可能會導致結果切片中資料遺失或空白,因為 goroutine 可能會交錯其操作並覆蓋彼此的變更。
使用「-race」選項驗證資料爭用
使用「-race」選項執行程式碼將為偵測到的每個資料爭用產生警告。以下輸出說明了所提供程式碼中的資料競爭條件:
================== WARNING: DATA RACE Read at 0x00c420074000 by goroutine 6: main.main.func1() /home/icza/gows/src/play/play.go:20 +0x69 Previous write at 0x00c420074000 by goroutine 5: main.main.func1() /home/icza/gows/src/play/play.go:20 +0x106 Goroutine 6 (running) created at: main.main() /home/icza/gows/src/play/play.go:21 +0x1cb Goroutine 5 (running) created at: main.main() /home/icza/gows/src/play/play.go:21 +0x1cb ==================
解決方案:使用互斥體進行同步
為了確保執行緒安全的並發追加,您可以使用互斥體來保護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()
透過在每次追加操作之前取得互斥體,可以防止多個goroutine 同時修改切片頭,從而確保資料完整性並消除資料競爭條件。
以上是為什麼在 Go 中附加到切片是線程不安全的?的詳細內容。更多資訊請關注PHP中文網其他相關文章!