データ競合シナリオにおけるゴルーチンの奇妙な動作を理解する
提供された Go コードでは、data と呼ばれる構造体フィールドのスライスを作成します。 「one」、「two」、「three」という名前が含まれています。コードはスライスを反復処理し、print メソッドを使用して各フィールドの名前を出力するゴルーチンを作成します。ただし、予想に反して、コードは意図した "one"、"two"、"three" の順序ではなく、"three" を 3 回繰り返し出力します。
データ競合の解明
この奇妙な動作は、複数のゴルーチンが同じ共有データに同時にアクセスし、変更する可能性があるときに発生するデータ競合に起因します。この場合、ゴルーチンの作成時に範囲変数 v のアドレスが暗黙的に使用されるために問題が発生します。ループ変数 v が各反復で変更されると、ゴルーチンは最終値を使用することになり、その結果、常に「three」が出力されます。
データ競合への対処
この問題を解決するには、いくつかの方法を採用できます。アプローチ:
各ループ反復での新しい変数の作成: ループ内で、範囲変数と同じ名前の新しい変数を宣言し、効果的に変数を作成できます。の新しいスコープvariable.
ポインターのスライスの使用: 構造体フィールドのスライスを使用する代わりに、フィールドへのポインターのスライスを使用できます。これにより、ゴルーチンが個々のフィールド要素へのポインタを確実に受け取り、データ競合の問題を防ぐことができます。
スライス要素のアドレスを渡す: 別の代替方法は、次のとおりです。スライス内の各要素のアドレスをgoroutine.
匿名関数の使用と引数として範囲変数の受け渡し: goroutine 関数が匿名関数内にある場合、次のように渡すことで問題を回避できます。への引数としての範囲変数function.
これらのアプローチにより、ゴルーチンが必要なデータの独自のコピーを確実に保持し、データ競合が排除され、「one」、「two、」の正しい出力が生成されます。 「」と「3」は順不同です。
以上がGo ルーチンのデータ競合で、Go コードが「One」、「Two」、「Three」ではなく「Three」を 3 回出力するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。