「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > 変数をインクリメントするゴルーチンが予期しない結果を生成するのはなぜですか?

変数をインクリメントするゴルーチンが予期しない結果を生成するのはなぜですか?

2024 年 11 月 5 日に公開
ブラウズ:351

Why Does My Goroutine Incrementing a Variable Produce Unexpected Results?

これはコンパイラの最適化の結果ですか?

このコード スニペットでは、ゴルーチンが起動され、変数 i:

package main

import "time"

func main() {
    i := 1
    go func() {
        for {
            i  
        }
    }()
    

ただし、出力は常に 1 です。この動作は、Go メモリ モデルとこのコードの特定の実装に起因すると考えられます。

Go メモリ モデル

Go メモリ モデルは、1 つのゴルーチン内の変数の読み取りが、別のゴルーチン内の同じ変数への書き込みによって生成された値を観察することを保証できる条件を定義します。これは、共有データへの同時アクセスにおける同期の重要性を強調しています。

同期の省略

指定されたコード内:

  • i への代入 (つまり、 i )の後には同期イベントが続かず、変更が他のゴルーチンにすぐに表示されない可能性があることを示しています。
  • コンパイラは、このループの最適化を操作なしに単純化することで最適化できます。

]コンパイラによる最適化

積極的なコンパイラは i ステートメントを削除し、ゴルーチンを効果的に次のように削減する可能性があります。

for {}

同期を使用した例

問題が同期の欠如に起因していることを示すために、次のコードを検討してください:

package main

import (
    "sync"
    "time"
)

func main() {
    mx := new(sync.Mutex)
    i := 1
    go func() {
        for {
            mx.Lock()
            i  
            mx.Unlock()
        }
    }()
    

この場合、予想どおり、出力は 1 ではなく、大きな数になります。 sync.Mutex は同期を提供し、両方のゴルーチンが制御された方法で i にアクセスすることを保証します。これにより、ゴルーチンが i をインクリメントし、変更がメイン ルーチンに表示されるようになります。

最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3