追加は本当にスレッドセーフですか?
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 サイトの他の関連記事を参照してください。