我构建了以下 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条经验 获得超4个赞
您有四个正在运行的 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 关注
- 101 浏览
添加回答
举报
0/150
提交
取消