ホームページ > バックエンド開発 > Golang > このゴルーチン コードが予期しない結果を生み出すのはなぜですか?また、データ競合を回避するにはどうすればよいですか?

このゴルーチン コードが予期しない結果を生み出すのはなぜですか?また、データ競合を回避するにはどうすればよいですか?

Linda Hamilton
リリース: 2024-12-11 18:36:12
オリジナル
485 人が閲覧しました

Why Does This Goroutine Code Produce Unexpected Results and How Can Data Races Be Avoided?

Goroutine の動作におけるデータ競合

提供されたコード スニペットでは、予測不可能な結果を​​引き起こす可能性のあるデータ競合の問題が発生します。中心的な問題は、ゴルーチンの性質と、範囲変数がゴルーチンの関数に渡される方法に起因します。

データ競合

提供されたコードは範囲を使用しています。データスライスをループし、反復ごとに新しいゴルーチンを開始してフィールド構造体の名前フィールドを出力します。ただし、各反復内では、範囲変数 v はデータ スライス内の同じ基礎となるデータ構造 (参照) を指します。

ループが進行し、変数 v がデータ スライスを反復処理するにつれて、その値は次のように変化します。次の要素を指します。これは、ゴルーチンの関数が実行されるまでに、スライス内の最後の要素である v の最後の値が設定されていることを意味します。

したがって、ゴルーチンの実行により、ゴルーチンの名前フィールドが出力されます。最後の要素である「three」だけが、意図された「one」、「two」、「three」の代わりに 3 回表示されます。

解決策

この問題を解決するには、いくつかの解決策が利用可能です:

  1. 新しい変数を作成する:

    • 新しい変数を導入しますv その反復のみを範囲とするループ反復内。これにより、各ゴルーチンが、スライス内の正しい要素を指す v の独自のバージョンを持つことが保証されます。
  2. ポインターのスライスを使用する:

    • 直接参照ではなくフィールド構造体へのポインターを保持するようにデータ スライスを変更します。このようにして、ループの各反復で特定の要素へのポインターを取得し、変数の上書きの問題を排除します。
  3. スライス要素のアドレスを使用します。

    • 範囲ループ中にスライス要素のアドレスを明示的に取得します。これにより、各ゴルーチンにスライス内の特定の要素への正しいアドレスが提供されます。

追加のアプローチ

  • 匿名関数に引数を渡す:ゴルーチン内で匿名関数を使用して範囲を渡します変数を引数として使用します。これにより、各ゴルーチンが範囲変数の固有のコピーにアクセスできるようになります。
  • Pointer Receiver: コードでは、構造体メソッド (field.print()) を使用します。 ) ポインターレシーバー付き。この実装では通常、問題を回避するためにデータ スライスのポインタのスライスの使用が保証されます。

以上がこのゴルーチン コードが予期しない結果を生み出すのはなぜですか?また、データ競合を回避するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート