スライスへの追加がスレッドセーフではない理由
複数のゴルーチンがスライスにデータを同時に追加しようとすると、データ競合状態が発生する可能性があります。起こる。これは、Go のスライスがスレッドセーフではないためです。つまり、複数のゴルーチンが同じスライス ヘッダーに同時にアクセスして変更することができ、データ破損を引き起こす可能性があります。
データ競合の図
次のコードを考えてみましょう:
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()
このコードでは、複数のゴルーチンが同時に destSlice スライスに追加されます。ゴルーチンは操作をインターリーブし、互いの変更を上書きする可能性があるため、結果のスライスでデータが欠落したり空白になったりする可能性があります。
「-race」オプションによるデータ競合の検証
「-race」オプションを指定してコードを実行すると、データ競合が検出されるたびに警告が生成されます。次の出力は、提供されたコードのデータ競合状態を示しています。
================== WARNING: DATA RACE Read at 0x00c420074000 by goroutine 6: main.main.func1() /home/icza/gows/src/play/play.go:20 +0x69 Previous write at 0x00c420074000 by goroutine 5: main.main.func1() /home/icza/gows/src/play/play.go:20 +0x106 Goroutine 6 (running) created at: main.main() /home/icza/gows/src/play/play.go:21 +0x1cb Goroutine 5 (running) created at: main.main() /home/icza/gows/src/play/play.go:21 +0x1cb ==================
解決策: 同期にミューテックスを使用する
スレッドセーフな同時追加を確保するには、次のようにします。ミューテックスを使用して destSlice スライス ヘッダーを保護できます。次の変更されたコードは、これを示しています。
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()
各追加操作の前にミューテックスを取得することで、複数のゴルーチンが同時にスライス ヘッダーを変更するのを防ぎ、データの整合性を確保し、データ競合状態を排除します。
以上がGo でのスライスへの追加がスレッドセーフではないのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。