理解資料競爭場景中Goroutine 的奇怪行為
在提供的Go 程式碼中,我們建立了一個名為data 的結構體欄位切片包含名稱「一」、「二」和「三」。該程式碼迭代切片,建立 goroutine 以使用 print 方法列印每個欄位的名稱。然而,與預期相反,代碼重複列印“三”三次,而不是預期的“一”、“二”和“三”順序。
揭開資料爭用
這種奇怪的行為源自於資料競爭,當多個goroutine 存取並可能同時修改相同的共用資料時就會發生這種情況。在這種情況下,問題是由於創建 goroutine 時隱式使用範圍變數 v 的位址而引起的。當循環變數 v 在每次迭代中更改時,goroutine 最終會使用其最終值,從而導致不斷列印「三」。
解決資料爭用
為了解決這個問題,我們可以採用幾種方法:
在每次循環迭代中建立一個新變數:在循環中,我們可以聲明一個與範圍變數同名的新變量,從而有效地創建變數的新範圍。
for _, v := range data { v := v // Declare a new variable `v` within the loop scope. go v.print() }
使用指標切片: 我們可以使用指向欄位的指標切片,而不是使用結構體欄位切片。這可以確保 goroutine 接收指向各個欄位元素的指針,從而防止資料競爭問題。
data := []*field{ {"one"},{"two"},{"three"} } for _, v := range data { go v.print() }
傳遞切片元素的位址:另一種替代方法是將切片中每個元素的位址傳遞給goroutine.
for i := range data { v := &data[i] // Take the address of the slice element. go v.print() }
使用匿名函數並傳遞範圍變數作為參數:如果goroutine函數位於匿名函數內,我們可以透過傳遞來避免此問題範圍變數作為參數
for _, v := range data { go func(v field) { // Pass the range variable `v` as an argument. v.print() }(v) }
這些方法確保goroutine 擁有自己所需資料的副本,消除資料競爭並生成“一”、“二”的正確輸出, ”和“三”,順序不限。
以上是為什麼我的 Go 代碼在 Goroutine 數據爭用中打印了三次'三”而不是'一”、'二”和'三”?的詳細內容。更多資訊請關注PHP中文網其他相關文章!