2 回答
TA贡献1895条经验 获得超3个赞
关闭 channel2 后,为什么第一个不执行?
通道不执行。一遍又一遍地执行的是您的选择。请注意,无论通道是否关闭,这两种情况都可以始终执行。所以 select 可以选择 id 所做的第二种情况,而你中止了。(你的中止条件看起来可疑:一旦两个通道都关闭,即如果ok1和 ok2 都为假,你就完成了)。
不要将 select 本身视为“goroutine 调度工具”。它不是。它将随机选择一个可运行的案例。如果您所有的案例都是可val, ok := <- ch
运行的,那么 select 可能总是选择第二个。或第一个,或...
[第二个解决方案]我现在更加困惑是怎么回事了。
您的中止条件不同。一旦两个通道都为零,您就会中断,这会在两个通道都关闭后发生。这与您的第一个解决方案不同,因为一旦任何 一个通道关闭,第一个就会中断。
这里的并发性问题不是 goroutine 调度,而只是你的 for 循环执行选择的中止条件。它们不同于第一个和第二个,第一个从根本上是错误的,因为一旦任何通道耗尽它就会停止。
TA贡献1784条经验 获得超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在他的一个案例完成之前一直处于阻塞状态。让我们先说case r2, ok2 := <-ch2:满足,然后continue2才是true。由于shouldContinue = continue1 || continue2这种情况,for循环将继续。出于某种原因(去例行调度)case r2, ok2 := <-ch2:条件每次都满足。现在当关闭时ch2,价值ok2也会false如此。现在, 和都是,也将是。因此它打破了循环,你看不到输出。试试这个: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
}
当一个通道关闭时,你不能在这个通道上发送值,但你仍然可以从通道接收。
Nil 通道总是阻塞,并且您还更改了for循环中断逻辑。这就是您的第二个解决方案有效的原因。
- 2 回答
- 0 关注
- 132 浏览
添加回答
举报