Go 並發和通道混亂
在 Go 中,並發允許使用 goroutine 並發執行多個任務。通道促進這些 goroutine 之間的通信。然而,理解並發性可能具有挑戰性,尤其是在處理通道時。
考慮以下程式碼片段:
<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>
在這段程式碼中,我們建立了兩個 goroutine:display 和 sum。 display goroutine 列印訊息,向通道發送訊號,然後等待回應。 sum goroutine 執行長時間計算,列印結果,並向通道發送訊號。在主 goroutine 中,我們會阻塞,直到從通道接收到訊號。
程式碼的預期輸出是:
display first message: hello
但是,我們觀察到程式列印了兩則訊息以及計算總和:
display first message: hello 10000000000
理解問題
問題的出現是由於goroutine 調度的不確定性。 Go 中的調度器在未被阻塞的 goroutine 之間自由選擇。在此範例中,調度程序可以在任何給定時間執行任何 goroutine。
一個可能的執行順序是:
在這種情況下,在顯示器發送訊號之前列印總和,導致意外的輸出。
解
為了確保程式只列印訊息並在計算總和之前退出,我們可以使用不同的方法:
<code class="go">func main() { result := make(chan string) go display("hello", result) go sum(result) fmt.Println(<-result) }</code>
在此修訂版本中,結果通道攜帶單一值,即來自顯示goroutine 的訊息。主 goroutine 現在會列印來自通道的值,確保它在退出之前收到訊息。
以上是為什麼 Go 程式會在給定程式碼片段中的訊息之前列印計算總和,即使主 Goroutine 會阻塞直到從通道接收到訊號?的詳細內容。更多資訊請關注PHP中文網其他相關文章!