Go 構造体の同時読み取りおよび書き込み: データ競合が発生する理由
Go では、ロックのない構造体に対する同時読み取りおよび書き込み操作により、潜在的にデータ競合につながります。これによって常に致命的なエラーが発生するわけではありませんが、根本的な問題を理解することが重要です。
構造におけるデータ競合の問題
データ競合は、複数のゴルーチンが同時に実行されると発生します。共有変数にアクセスし、それらのアクセスのうち少なくとも 1 つは書き込みです。構造体の場合、これは、2 つ以上のゴルーチンが同じ構造体の異なるフィールドを同時に読み書きできることを意味します。
複数のゴルーチンがメタデータ構造体を同時に読み書きする次の例を考えてみましょう。 :
type Metadata struct { key bool } func concurrentStruct() { m := new(Metadata) for i := 0; i < 100000; i++ { go func(metadata *Metadata) { for { readValue := metadata.key if readValue { metadata.key = false } } }(m) go func(metadata *Metadata) { for { metadata.key = true } }(m) } select {} }
この例は、警告: データ競合付きで実行されますが、致命的なエラーは発生しません。これは、データ競合が構造体の 1 つのフィールド (キー フィールド) でのみ発生するためです。他のフィールドにはアクセスされていないため、構造は安定したままであり、プログラムは実行を継続できます。
データ競合の解決
データ競合を排除するには、次のことを行う必要があります。ロックを使用して構造への同時アクセスを同期します。これを実現する 1 つの方法は、次の例に示すように、読み取り/書き込みミューテックスを使用することです。
type Metadata struct { mu sync.RWMutex key bool } func concurrentStructWithMuLock() { m := new(Metadata) go func(metadata *Metadata) { for { metadata.mu.Lock() readValue := metadata.key if readValue { metadata.key = false } metadata.mu.Unlock() } }(m) go func(metadata *Metadata) { for { metadata.mu.Lock() metadata.key = true metadata.mu.Unlock() } }(m) select {} }
読み取り/書き込みミューテックスを追加すると、データ競合が解消され、プログラムが実行されます。エラーメッセージなしで。これは、ミューテックスによって、一度に 1 つの goroutine のみが構造体にアクセスできるようにするためです。
結論として、Go の構造体に対する同時読み取りおよび書き込み操作は、構造体に複数のフィールドがある場合でも、データ競合を引き起こす可能性があります。データ競合を防止し、同時実行プログラムの正しい動作を保証するには、読み取り/書き込みミューテックスなどの同期メカニズムを使用することが重要です。
以上がGo 構造体での同時読み取りおよび書き込み操作はどのようにしてデータ競合を引き起こすのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。