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

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

Mary-Kate Olsen
リリース: 2024-12-08 17:37:11
オリジナル
214 人が閲覧しました

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

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