これはコンパイラの最適化の結果ですか?
このコード スニペットでは、ゴルーチンが起動され、変数 i:
<code class="go">package main
import "time"
func main() {
i := 1
go func() {
for {
i++
}
}()
<-time.After(1 * time.Second)
println(i)
}</code>
ログイン後にコピー
ただし、出力は常に 1 です。この動作は、Go メモリ モデルとこのコードの特定の実装に起因すると考えられます。
Go メモリ モデル
Go メモリ モデルは条件を定義しますこれにより、あるゴルーチン内の変数の読み取りが、別のゴルーチン内の同じ変数への書き込みによって生成された値を観察することが保証されます。これは、共有データへの同時アクセスにおける同期の重要性を強調しています。
同期の省略
指定されたコード内:
i への代入 (つまり、 i )の後には同期イベントが続かず、変更が他のゴルーチンにすぐに表示されない可能性があることを示します。- コンパイラは、このループの最適化を操作なしに単純化することで最適化する場合があります。
-
コンパイラによる最適化
積極的なコンパイラは i ステートメントを削除し、ゴルーチンを効果的に次のように削減する可能性があります。
<code class="go">for {}</code>
ログイン後にコピー
同期を使用した例
問題の原因を示すため同期が取れていないため、次のコードを考慮してください。
<code class="go">package main
import (
"sync"
"time"
)
func main() {
mx := new(sync.Mutex)
i := 1
go func() {
for {
mx.Lock()
i++
mx.Unlock()
}
}()
<-time.After(1 * time.Second)
mx.Lock()
println(i)
mx.Unlock()
}</code>
ログイン後にコピー
この場合、出力は 1 ではなく、予想どおり大きな数値になります。 sync.Mutex は同期を提供し、両方のゴルーチンが制御された方法で i にアクセスすることを保証します。これにより、ゴルーチンが i をインクリメントし、変更がメイン ルーチンに表示されるようになります。
以上が変数をインクリメントするゴルーチンが予期しない結果を生成するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。