同時実行 Go ルーチンでのデータ競合
このコードは、同時実行 Go でのデータ競合の問題を示しています。ルーチン:
package main import ( "fmt" "time" ) type field struct { name string } func (p *field) print() { fmt.Println(p.name) } func main() { data := []field{{"one"}, {"two"}, {"three"}} for _, v := range data { go v.print() } <-time.After(1 * time.Second) }
問題:
コードは、どのコードでも「one」、「two」、「three」を出力するのではなく、「three」を 3 回出力します。注文。これは、データ競合が存在するためです。
説明:
コードは、ゴルーチン関数の引数を評価するときに、暗黙的に変数 v のアドレスを取得します。ゴルーチン関数 v.print() は (&v).print() と同等です。ループは v の値を変更し、ゴルーチンが実行されると、たまたまループの最後の値 (「three」) を持ちます。
修正:
このデータ競合を修正するには、いくつかの方法があります。
for _, v := range data { v := v // short variable declaration of new variable `v`. go v.print() }
data := []*field{{"one"}, {"two"}, {"three"}} // note '*' for _, v := range data { go v.print() }
data := []field{{"one"}, {"two"}, {"three"}} // note '*' for i := range data { v := &data[i] go v.print() }
for _, v := range data { go func(v field) { v.print() // take address of argument v, not range variable v. }(v) }
以上がGo でゴルーチンを起動するときにデータ競合を回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。