2 回答

TA貢獻1873條經驗 獲得超9個贊
有些代碼路徑不會打印某些消息done
。調度程序碰巧選擇了一個不打印 的那個multiply
。如果您稍微更改代碼(例如,在與現在不同的實例上登錄),您會發現它也可能會錯過該消息add
?done
。原因如下:
如果done
消息在生成器將數字寫入通道并且乘法器讀取它之后立即到達,則乘法器會看到該數字done
可用并選擇該數字。multiplier
打印消息時就是這種情況done
。如果當done
multiplier 在 for 循環中等待時消息到達,則 multiplier 將接收輸入通道(而不是通道)上的關閉消息done
,從而導致 for 循環終止而不打印done
消息。
出現問題的原因是您正在 for 循環中讀取通道,然后進行選擇。在等待 for 循環從通道讀取數據時,不會評估與 select 相關的任何事件。
處理此問題的更好方法是不使用 for 循環從通道讀取。例如:
for {
? ? ?select {
? ? ? ? case <-done:
? ? ? ? ? ?return
? ? ? ? case i, ok:= <-intstream:
? ? ? ? ? ?if !ok {
? ? ? ? ? ? ? return
? ? ? ? ? ?}
? ? ? ? ? ?select {
? ? ? ? ? ? ? ?case <- done:
? ? ? ? ? ? ? ? ? ? return
? ? ? ? ? ? ? ?case addedStream <- i + additive:
? ? ? ? ? ?}
? ? ?}
}

TA貢獻1836條經驗 獲得超5個贊
你的add
例程multiply
不是永遠循環,而是for ... range
循環。因此,在每個循環的頂部,它們等待下一個整數,而不是等待從其流select
接收關閉done
或將結果發送到其流。這不是問題,但這意味著如果它們的輸入流關閉,它們將返回而不進入循環本身。
如果我添加fmt.Println
調用來公開它們由于到達輸入流末尾而退出的點,則行為會略有變化(可能是由于時間原因;同時我正在輸入這個),輸出變成:
add after select
2
multiply after select
generator after select
multiply after select
add after select
4
generator after select
multiply after select
add after select
6
generator after select
Closed done
done multiply !
add got end of stream - done!
finished iterating pipeline
generator after select
done generator!
ramaining goroutines: 1
finished!
通常更合理的做法是僅讓生成器本身接收done信號,并讓管道函數始終寫入其所有結果,這使它們更可預測。當然,無論誰正在讀取每個管道,都必須讀到最后——但是您已經在主 goroutine 中執行了此操作,因此我們只是將其傳播到整個管道。 這是您的代碼的簡化版本,以這種方式執行此操作;它輸出:
2
generator after select
4
generator after select
6
generator after select
Closed done
8
generator after select
done generator!
multiply got end of stream - done!
add got end of stream - done!
finished iterating pipeline
remaining goroutines: 1
請注意,這一次,我們從最終生成值 (3) 中得到最終計算值 (8)。
- 2 回答
- 0 關注
- 170 瀏覽
添加回答
舉報