ホームページ  >  記事  >  バックエンド開発  >  Go での Append は Goroutine で使用するとスレッドセーフになりますか?

Go での Append は Goroutine で使用するとスレッドセーフになりますか?

Linda Hamilton
Linda Hamiltonオリジナル
2024-11-11 07:53:02533ブラウズ

Is Append in Go Thread-Safe When Used with Goroutines?

追加は本当にスレッドセーフですか?

Go で共有リソースへの同時アクセスを処理する場合、同期は非常に重要です。一般的な方法は、ゴルーチンを使用して要素をスライスに追加することです。ただし、append 関数は本質的にスレッドセーフではありません。

上記のケースでは、スライスに追加するためにループ内に個別のゴルーチンを作成すると、データの不整合が発生する可能性があります。これは、複数のゴルーチンが同じスライスに同時に書き込むとデータ競合が発生する可能性があるためです。

これを示すために、次のコード スニペットを考えてみましょう:

destSlice := make([]myClass, 0)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        destSlice = append(destSlice, tmpObj)
    }(myObject)
}
wg.Wait()

-race オプションを使用してこのコードを実行します。複数のデータ競合が明らかになります。このような競合を防ぐには、ミューテックスなどの同期メカニズムを使用する必要があります。以下は、ミューテックスを使用して修正されたコード スニペットです:

var (
    mu        = &sync.Mutex{}
    destSlice = make([]myClass, 0)
)

var wg sync.WaitGroup
for _, myObject := range sourceSlice {
    wg.Add(1)
    go func(closureMyObject myClass) {
        defer wg.Done()
        var tmpObj myClass
        tmpObj.AttributeName = closureMyObject.AttributeName
        mu.Lock()
        destSlice = append(destSlice, tmpObj)
        mu.Unlock()
    }(myObject)
}
wg.Wait()

別の解決策は、ゴルーチンが追加される値を送信するチャネルを使用することです。専用の goroutine は、これらの値の受信を処理し、追加操作を実行できます。

要約すると、スライス要素は個別の変数であり、同期なしで同時にアクセスできますが、スライス ヘッダーには、同時追加操作中のデータ競合を防ぐための同期が必要です。

以上がGo での Append は Goroutine で使用するとスレッドセーフになりますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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