我構建了以下 go 代碼。這個想法是構建一個完成通道和一個生成 int 通道的生成器。將它們鏈接到一個 2 階段管道 chanNumbers := pipelineb(done, pipelinea(done, gen(done)))幾秒鐘后,取消已完成的通道。我希望看到生成器和管道的兩級取消并返回,但文本“PipeX 現在終止”僅隨機出現,我真的不明白為什么。有人有主意嗎?package mainimport ( "fmt" "time")func gen(done <-chan interface{}) <-chan int { ret := make(chan int) cx := 0 go func() { for { select { case <-done: fmt.Println("**Generator Terminates now") time.Sleep(2 * time.Second) fmt.Println("**Generator has terminated now") close(ret) return case ret <- cx: fmt.Printf("Gen : we push %d \n", cx) cx = cx + 1 } } }() fmt.Println("Generator has created and returned its channel") return ret}func pipea(done <-chan interface{}, in <-chan int) <-chan int { ret := make(chan int) go func() { for { select { case <-done: fmt.Println("**pipeA terminates") time.Sleep(2 * time.Second) fmt.Println("**pipeA has terminated now") close(ret) return case tmp, ok := (<-in): if ok { fmt.Printf("pipeA : we push %d \n", tmp) ret <- tmp } else { in = nil } } } }() return ret}func pipeb(done <-chan interface{}, in <-chan int) <-chan int { ret := make(chan int) go func() { for { select { case <-done: fmt.Println("**pipeB terminates") time.Sleep(2 * time.Second) fmt.Println("**pipeB has terminated now") close(ret)
1 回答

收到一只叮咚
TA貢獻1821條經驗 獲得超5個贊
您有四個正在運行的 go 例程:
gen
,你的生成器,寫入無緩沖的輸出通道,直到done
pipeA
,從 讀取gen
,寫入無緩沖的輸出通道,直到done
pipeB
,從 讀取pipeA
,寫入無緩沖的輸出通道,直到done
main
,從pipeB
讀到done
現在,當您關閉時done
,它完全取決于 go 例程看到它的順序。
如果main
是第一個看到它done
已關閉,它將打破 for 循環并停止消耗pipeB
。但是如果pipeB
仍然嘗試寫入輸出通道(ret <- tmp
),它將在那里阻塞;所以它永遠不會到達該<- done
部分。
有兩個選項可以解決此問題:
只在你的生成器中監聽
done
,并讓其他 go 例程使用for n := range in { }
.select
將您的發送邏輯也放入 a 中,以便您的生成器和管道可以檢測何時done
關閉。
或者,您可能希望使用緩沖輸出通道,但即使如此,此問題仍然可能發生。
- 1 回答
- 0 關注
- 133 瀏覽
添加回答
舉報
0/150
提交
取消