2 回答

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

TA貢獻1784條經(jīng)驗 獲得超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在他的一個案例完成之前一直處于阻塞狀態(tài)。讓我們先說case r2, ok2 := <-ch2:滿足,然后continue2才是true。由于shouldContinue = continue1 || continue2這種情況,for循環(huán)將繼續(xù)。出于某種原因(去例行調(diào)度)case r2, ok2 := <-ch2:條件每次都滿足?,F(xiàn)在當(dāng)關(guān)閉時ch2,價值ok2也會false如此?,F(xiàn)在, 和都是,也將是。因此它打破了循環(huán),你看不到輸出。試試這個: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
}
當(dāng)一個通道關(guān)閉時,你不能在這個通道上發(fā)送值,但你仍然可以從通道接收。
Nil 通道總是阻塞,并且您還更改了for循環(huán)中斷邏輯。這就是您的第二個解決方案有效的原因。
- 2 回答
- 0 關(guān)注
- 170 瀏覽
添加回答
舉報