ホームページ >バックエンド開発 >Golang >Go でゴルーチンを起動するときにデータ競合を回避するにはどうすればよいですか?

Go でゴルーチンを起動するときにデータ競合を回避するにはどうすればよいですか?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-12-08 17:37:11228ブラウズ

How to Avoid Data Races When Launching Goroutines in Go?

同時実行 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 サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。