ホームページ >バックエンド開発 >Golang >Go 構造体の読み取りと書き込みを同時に行うときにデータ競合を防ぐにはどうすればよいですか?

Go 構造体の読み取りと書き込みを同時に行うときにデータ競合を防ぐにはどうすればよいですか?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-12-25 04:21:09542ブラウズ

How Can I Prevent Data Races When Concurrently Reading and Writing Go Structs?

明示的なロックを使用しない Go 構造体の同時読み取りと書き込み

Go での共有データへの同時アクセスは、データ競合などの潜在的なエラーの原因となる可能性があります。データ構造へのアクセスが同時である場合、つまり複数のゴルーチンが同時にアクセスできる場合、不整合を避けるためにデータの読み取りと書き込みが同期された方法で行われるようにすることが重要です。

構造体への同時アクセス

次の Go 構造体を考えてみましょうメタデータ:

type Metadata struct {
    mu  sync.RWMutex // ?
    key bool
}

ご覧のとおり、メタデータ構造体には bool 型のフィールド キーと、読み取り/書き込みロックの実装である sync.RWMutex 型の別のフィールド mu が含まれています。

構造体でのデータ競合

メタデータのインスタンスを作成し、複数のゴルーチンがフィールドの読み取りと書き込みを同時に行うと、データ競合が発生する可能性があります。データ競合は、複数のゴルーチンが同じデータに同時にアクセスし、そのうちの少なくとも 1 つが書き込み操作を実行している場合に発生します。

次のコードは、明示的なロックを使用しないメタデータ構造体への同時読み取りおよび書き込みアクセスを示しています。

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 {}
}

このコードでは、キー フィールドの読み取りと書き込みを同時に行う goroutine を作成します。 select ステートメントを使用してメインの goroutine をブロックし、同時 goroutine の実行を許可します。 go run -race コマンドを使用してプログラムを実行すると、DATA RACE を示す警告が表示されます。

ただし、プログラムはクラッシュせずに実行を続けます。これは、Go ランタイムには同時実行チェックが組み込まれているためですが、安全な実行が保証されているわけではありません。この場合、データ競合により、未定義の動作や不正確な結果が生じる可能性があります。

構造体でのデータ競合の解決

構造体への同時読み取りと書き込み時にデータ競合を防ぐには、適切なメソッドを使用する必要があります。ロック機構。 1 つの方法は、次のコードに示すように、ミューテックスを使用することです。

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 {}
}

このコードでは、メタデータ構造体に読み取り/書き込みロックを追加し、mu.Lock() と mu を使用します。 Unlock() を使用して、キー フィールドへのアクセスを同期します。 go run -race を指定してプログラムを実行すると、データ競合がないことを示す警告が生成されなくなりました。

以上がGo 構造体の読み取りと書き込みを同時に行うときにデータ競合を防ぐにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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