2 回答

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

TA貢獻1836條經(jīng)驗 獲得超5個贊
你的add
例程multiply
不是永遠循環(huán),而是for ... range
循環(huán)。因此,在每個循環(huán)的頂部,它們等待下一個整數(shù),而不是等待從其流select
接收關(guān)閉done
或?qū)⒔Y(jié)果發(fā)送到其流。這不是問題,但這意味著如果它們的輸入流關(guān)閉,它們將返回而不進入循環(huán)本身。
如果我添加fmt.Println
調(diào)用來公開它們由于到達輸入流末尾而退出的點,則行為會略有變化(可能是由于時間原因;同時我正在輸入這個),輸出變成:
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信號,并讓管道函數(shù)始終寫入其所有結(jié)果,這使它們更可預(yù)測。當(dāng)然,無論誰正在讀取每個管道,都必須讀到最后——但是您已經(jīng)在主 goroutine 中執(zhí)行了此操作,因此我們只是將其傳播到整個管道。 這是您的代碼的簡化版本,以這種方式執(zhí)行此操作;它輸出:
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 關(guān)注
- 186 瀏覽
添加回答
舉報