2 回答

TA貢獻1895條經驗 獲得超3個贊
關閉 channel2 后,為什么第一個不執行?
通道不執行。一遍又一遍地執行的是您的選擇。請注意,無論通道是否關閉,這兩種情況都可以始終執行。所以 select 可以選擇 id 所做的第二種情況,而你中止了。(你的中止條件看起來可疑:一旦兩個通道都關閉,即如果ok1和 ok2 都為假,你就完成了)。
不要將 select 本身視為“goroutine 調度工具”。它不是。它將隨機選擇一個可運行的案例。如果您所有的案例都是可val, ok := <- ch
運行的,那么 select 可能總是選擇第二個?;虻谝粋€,或...
[第二個解決方案]我現在更加困惑是怎么回事了。
您的中止條件不同。一旦兩個通道都為零,您就會中斷,這會在兩個通道都關閉后發生。這與您的第一個解決方案不同,因為一旦任何 一個通道關閉,第一個就會中斷。
這里的并發性問題不是 goroutine 調度,而只是你的 for 循環執行選擇的中止條件。它們不同于第一個和第二個,第一個從根本上是錯誤的,因為一旦任何通道耗盡它就會停止。

TA貢獻1784條經驗 獲得超7個贊
在你的代碼的第一部分,你的邏輯有錯誤。
shouldContinue := true
var continue1, continue2 bool
for shouldContinue {
? ? select {
? ? case r1, ok1 := <-ch1:
? ? ? ? fmt.Println("[ch1] [rcvd]", r1)
? ? ? ? continue1 = ok1
? ? case r2, ok2 := <-ch2:
? ? ? ? fmt.Println("[ch2] [rcvd]", r2)
? ? ? ? continue2 = ok2
? ? }
? ? shouldContinue = continue1 || continue2
}
在上面的代碼中,continue1和continue2是false. select在他的一個案例完成之前一直處于阻塞狀態。讓我們先說case r2, ok2 := <-ch2:滿足,然后continue2才是true。由于shouldContinue = continue1 || continue2這種情況,for循環將繼續。出于某種原因(去例行調度)case r2, ok2 := <-ch2:條件每次都滿足?,F在當關閉時ch2,價值ok2也會false如此?,F在, 和都是,也將是。因此它打破了循環,你看不到輸出。試試這個:continue2falsecontinue1continue2falseshouldContinuefalseforch1
continue1 = true
continue2 = true
for shouldContinue {
? ? select {
? ? case r1, ok1 := <-ch1:
? ? ? ? fmt.Println("[ch1] [rcvd]", r1)
? ? ? ? continue1 = ok1
? ? case r2, ok2 := <-ch2:
? ? ? ? fmt.Println("[ch2] [rcvd]", r2)
? ? ? ? continue2 = ok2
? ? }
? ? shouldContinue = continue1 || continue2
}
當一個通道關閉時,你不能在這個通道上發送值,但你仍然可以從通道接收。
Nil 通道總是阻塞,并且您還更改了for循環中斷邏輯。這就是您的第二個解決方案有效的原因。
- 2 回答
- 0 關注
- 156 瀏覽
添加回答
舉報