Golang 高併發編程For循環中使用Goroutine最容易犯的錯誤

file

Golang

goroutine是Go語言強大的特性之一,合理的利用它才能發揮最大的價值

1、經調查

發現初學者一般會犯以下錯誤使用goroutine

func goroutineRun(values []int)  {
    for value := range values {
        go value.test()
    }
}

或者使用閉包調用

func goroutineRun(values []int)  {
    for value := range values {
        go func() {
            fmt.Println(value)
        }()
    }
}

這2段代碼實際上是遍歷數組的所有變量。由於閉包只是綁定到這個value變量上,並沒有被保存到goroutine棧中,所以以上代碼極有可能運行的結構都輸出爲切片的最後一個元素。因爲這樣寫會導致for循環結束後才執行goroutine多線程操作,這時候value值只指向了最後一個元素。這樣的結果不是我們所希望的,而且還會產生併發的資源搶佔衝突所以是非常不推薦這樣寫的。

2、解決方法

goroutine的正確寫法

for val := range values {
    go func(val interface{}) {
        fmt.Println(val)
    }(val)
}

在這裏將 val 作爲一個參數傳入 goroutine 中,每個 val 都會被獨立計算並保存到 goroutine 的棧中,從而得到預期的結果。

另一種方法是在循環內定義新的變量,由於在循環內定義的變量在循環遍歷的過程中是不共享的,因此也可以達到同樣的效果:

for i := range valslice {
    val := valslice[i]
    go func() {
        fmt.Println(val)
    }()
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章