首頁 >後端開發 >Golang >為什麼我的 Go 代碼在 Goroutine 數據爭用中打印了三次'三”而不是'一”、'二”和'三”?

為什麼我的 Go 代碼在 Goroutine 數據爭用中打印了三次'三”而不是'一”、'二”和'三”?

Linda Hamilton
Linda Hamilton原創
2024-12-07 22:23:13906瀏覽

Why Does My Go Code Print

理解資料競爭場景中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中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn