2017-07-24 100 views
-2

我有for循環與goroutines。我在循環中創建了打印一個字符串和「我」這是一個int的去例程。我知道字符串,「我」會按照隨機順序打印。但是,「我」沒有正確添加,如下所示。五個字符串中的三個或四個字符串的值保持不變,然後跳轉到2或1.不應該有隨機順序中的1,2,3,4,5個字符嗎?我究竟做錯了什麼?Golang for循環加入i ++不一致

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    a := []string{ 
     "apple", 
     "orange", 
     "grape", 
     "peach", 
     "lemon", 
    } 

    wg := sync.WaitGroup{} 
    wg.Add(len(a)) 
    i := 0 
    for _, v := range a { 
     go func(a string) { 
      fmt.Println(a, i) 
      i++ 
      wg.Done() 
     }(v) 
    } 
    wg.Wait() 
} 

結果1:

orange 0 
apple 0 
lemon 0 
peach 2 
grape 0 

結果2:

lemon 0 
grape 0 
peach 0 
apple 0 
orange 1 

我的目標(隨機順序)

lemon 2 
grape 4 
peach 1 
apple 0 
orange 3 

回答

5

通過封閉件的所有夠程共享相同的變量i。嘗試改爲:

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    a := []string{ 
     "apple", 
     "orange", 
     "grape", 
     "peach", 
     "lemon", 
    } 

    wg := sync.WaitGroup{} 
    wg.Add(len(a)) 
    for i, v := range a { 
     go func(a string, j int) { 
      fmt.Println(a, j) 
      wg.Done() 
     }(v,j) 
    } 
    wg.Wait() 
} 

一般:在節目中你發佈你正在閱讀i,並從不同的夠程沒有任何同步寫i。這是一場數據競賽。在這種情況下可能發生任何事情。

圍棋比賽探測器甚至罵你

go run -race test.go 
apple 0 
================== 
WARNING: DATA RACE 
Read at 0x00c420010268 by goroutine 7: 
    main.main.func1() 
     /home/erwo/test.go:22 +0x6d 

Previous write at 0x00c420010268 by goroutine 6: 
    main.main.func1() 
     /home/erwo/test.go:23 +0x191 

Goroutine 7 (running) created at: 
    main.main() 
     /home/erwo/test.go:25 +0x15f 

Goroutine 6 (finished) created at: 
    main.main() 
     /home/erwo/test.go:25 +0x15f 
================== 
orange 1 
================== 
WARNING: DATA RACE 
Read at 0x00c420010268 by goroutine 8: 
    main.main.func1() 
     /home/erwo/test.go:22 +0x6d 

Previous write at 0x00c420010268 by goroutine 6: 
    main.main.func1() 
     /home/erwo/test.go:23 +0x191 

Goroutine 8 (running) created at: 
    main.main() 
     /home/erwo/test.go:25 +0x15f 

Goroutine 6 (finished) created at: 
    main.main() 
     /home/erwo/test.go:25 +0x15f 
================== 
peach 2 
grape 2 
lemon 4 
Found 2 data race(s) 
exit status 66 
+0

謝謝你向我解釋。我聽說過一場比賽的情況,但直到現在還不明白。 –

5

但是也有一些發生在每一個夠程幾件事情:

  1. 它打印出的i的價值,因爲它是當時打印語句執行
  2. 它遞增i的值。

不能保證這兩件事發生在原子上,或者它們按什麼樣的順序發生。

爲了得到你想要的結果,您可以:

  1. 使用互斥來保護訪問i(但還挺失敗有時paralellism點)
  2. i作爲參數傳遞給你的功能(go func(i int){}(i))。 (像克羅姆的答案)
  3. 使用原子操作來交換我到一個新的地方在每個goroutine中並加一(有點棘手得到恰到好處)

我建議2.但是,我也建議反對使用goroutine命令作爲隨機的來源。

+0

謝謝。我真正的程序正在處理數千行,這就是爲什麼我想在我的for循環中執行例程以節省時間。克羅姆的例子爲我工作。感謝您更好地解釋這一點。 –