2016-08-29 8 views
3

私はGoを学習し、その同時性機能を理解しようとしています。Golangはどのようにゴルーチン間で変数を共有しますか?

私は以下のプログラムを持っています。

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 

    for i := 0; i < 5; i++ { 
     wg.Add(1) 

     x := i 

     go func() { 
      defer wg.Done() 
      fmt.Println(x) 
     }() 

    } 

    wg.Wait() 
    fmt.Println("Done") 
} 

実行すると私が得た:

4 
0 
1 
3 
2 

それは私が欲しいだけのものです。私はそれに若干の修正を加えた場合しかし、私が得たもの

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 

    for i := 0; i < 5; i++ { 
     wg.Add(1) 

     go func() { 
      defer wg.Done() 
      fmt.Println(i) 
     }() 

    } 

    wg.Wait() 
    fmt.Println("Done") 
} 

は次のようになります。

5 
5 
5 
5 
5 

私はかなりの違いを理解していません。誰でもここで何が起こったのか、Go実行時にこのコードを実行する方法について説明できますか?

+3

FAQを参照してくださいに/golang.org/doc/faq#closures_and_goroutines – JimB

+1

[Go Memory Model](https://golang.org/ref/mem)も参照してください。 – icza

+0

可能な重複:https://stackoverflow.com/questions/24196200/closures-in-go-routines-have-incorrect-scope-unless-the-variables-are-copied、https://stackoverflow.com/questions/ 25919213/golang-handle-closure-different-in-goroutines – JimB

答えて

3

あなたはx := iの各実行に新しい変数を持って、
このコードは、ゴルーチン内xのアドレスを印刷して、うまく違いを示しています
The Go Playground

package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 
    for i := 0; i < 5; i++ { 
     wg.Add(1) 
     x := i 
     go func() { 
      defer wg.Done() 
      fmt.Println(&x) 
     }() 
    } 
    wg.Wait() 
    fmt.Println("Done") 
} 

出力:

0xc0420301e0 
0xc042030200 
0xc0420301e8 
0xc0420301f0 
0xc0420301f8 
Done 

そして、2番目の例を構築してくださいルgo build -raceとし、それを実行します。
あなたが表示されます。WARNING: DATA RACE


そして、これはThe Go Playground罰金になります:

//go build -race 
package main 

import (
    "fmt" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 
    for i := 0; i < 5; i++ { 
     wg.Add(1) 
     go func(i int) { 
      defer wg.Done() 
      fmt.Println(i) 
     }(i) 
    } 
    wg.Wait() 
    fmt.Println("Done") 
} 

は出力します。https::/

0 
4 
1 
2 
3 
Done 
+1

ありがとうございます。これは私に論理的な背後を理解するのを助けました。 – user130268

2

一般的なルールは、ゴルーチン間でデータを共有しないことです。最初の例では、基本的に各ゴルーチンにxという独自のコピーを与え、printステートメントにどのような順序で印刷するかを指定します。 2番目の例では、すべて同じループ変数を参照していますが、それらの変数を印刷するときには5までインクリメントされます。私はその出力が保証されているとは思わないが、goroutinesを作成するループが、goroutines自身が印刷部分に到達するよりも速く終了することが起こります。

関連する問題