原文連接:http://www.zhoubotong.site/post/19.html
html
你們可能常常會用到相似以下代碼片斷:post
package main import ( "fmt" "sync" "time" ) func main() { sli := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} wg := sync.WaitGroup{} for k, v := range sli { wg.Add(1) go func() { time.Sleep(time.Second) fmt.Println(k, v) wg.Done() }() } wg.Wait() }
打印輸出:spa
9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9
結果是否是和想象的不同?,主要緣由出在協程這裏,若是不使用協程,直接使用串行的方式,結果結合預期一致,好比:code
package main import ( "fmt" "time" ) func main() { sli := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} for k, v := range sli { func() { time.Sleep(time.Second) fmt.Println(k, v) }() } }
打印輸出:協程
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9
那爲何上面使用攜程的輸出都是相同值?咱們來解讀下:
其中 k, v 是迭代變量,每次迭代都會給 k, v 賦值新的值,而且多個協程又同時調用了 k, v ,因此結果就串了,那攜程怎麼解決?解決方式咱們能夠定義一個局部變量。htm
package main import ( "fmt" "sync" "time" ) func main() { sli := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} wg := sync.WaitGroup{} for k, v := range sli { wg.Add(1) k1 := k v1 := v go func() { time.Sleep(time.Second) fmt.Println(k1, v1) wg.Done() }() } wg.Wait() }
k1, v1 是局部變量,每次循環,循環體內是不共享的,這也是爲何能夠這樣聲明變量(k1 := k)。blog
或者經過傳參的方式來固定下來,好比像下面這樣:get
package main import ( "fmt" "sync" "time" ) func main() { sli := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} wg := sync.WaitGroup{} for k, v := range sli { wg.Add(1) go func(k, v interface{}) { time.Sleep(time.Second) fmt.Println(k, v) wg.Done() }(k, v) } wg.Wait() }
這樣輸出就正常,好比輸出以下:it
0 0 5 5 2 2 3 3 4 4 1 1 9 9 6 6 8 8 7 7