Go の同時実行性とチャネルの混乱
Go では、同時実行性により、ゴルーチンを使用して複数のタスクを同時に実行できます。チャネルは、これらのゴルーチン間の通信を容易にします。ただし、同時実行性を理解することは、特にチャネルを扱う場合に難しい場合があります。
次のコード スニペットを考えてみましょう。
<code class="go">package main import "fmt" func display(msg string, c chan bool) { fmt.Println("display first message:", msg) c <- true } func sum(c chan bool) { sum := 0 for i := 0; i < 10000000000; i++ { sum++ } fmt.Println(sum) c <- true } func main() { c := make(chan bool) go display("hello", c) go sum(c) <-c }</code>
このコードでは、display と sum という 2 つのゴルーチンを作成します。表示ゴルーチンはメッセージを出力し、チャネルに信号を送信して、応答を待ちます。 sum ゴルーチンは、長い計算を実行し、結果を出力し、チャネルに信号を送信します。メインのゴルーチンでは、チャネルからシグナルを受信するまでブロックします。
コードの期待される出力は次のとおりです。
display first message: hello
ただし、プログラムが両方のメッセージを出力することがわかります。計算の合計:
display first message: hello 10000000000
問題の理解
この問題は、ゴルーチンのスケジューリングの非決定的な性質により発生します。 Go のスケジューラは、ブロックされていないゴルーチンの中から自由に選択します。この例では、スケジューラはいつでも任意のゴルーチンを実行できます。
可能な実行順序の 1 つは次のとおりです。
このシナリオでは、ディスプレイが信号を送信する前に合計が出力されるため、予期しない出力が発生します。
解決策
プログラムがメッセージのみを出力し、合計が計算される前に終了するようにするには、別のアプローチを使用できます。
<code class="go">func main() { result := make(chan string) go display("hello", result) go sum(result) fmt.Println(<-result) }</code>
この改訂版では、結果チャネルは単一の値、つまり表示ゴルーチンからのメッセージを伝えます。メインの goroutine はチャネルからの値を出力し、終了する前にメッセージを確実に受信するようになりました。
以上がメインの goroutine はチャネルから信号を受信するまでブロックしているにもかかわらず、Go プログラムが指定されたコード スニペットのメッセージの前に計算の合計を出力するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。