【发布时间】:2020-11-21 19:18:35
【问题描述】:
我知道,如果在select 语句中可以进行多个“通信”,则随机选择一个。我正在尝试寻找一种替代方法,它可以更喜欢一种“交流”而不是另一种。
背景是我在一个使用上下文杀死的通道上的 go-routine 中发送值。当我杀死它时,我希望立即关闭通道,但目前代码有时会在关闭之前在通道上发送最终值。
下面是简化版的代码:
ctx, cancel := context.WithCancel(context.Background())
ch := make(chan int)
go func() {
defer close(ch)
for i := 1; ; i++ {
select {
case <-ctx.Done():
return
case ch <- i:
}
}
}()
print(<-ch)
print(<-ch)
cancel()
print(<-ch)
print(<-ch)
这有时会打印 1200,但通常会打印 1230。Try it on the playground
对于如何重组代码以支持第一种情况有什么想法吗? (即总是打印 1200。)
【问题讨论】:
-
这是非常不寻常的代码。通常在取消上下文后您不会收到来自 ch 的信息。无论如何,您没有理由期望在此处打印任何特定值。我认为这不是真实代码的有用近似值。
-
@Peter,这有点类似于
Timer.Reset()的情况 -
@BurakSerdar “只有在停止或过期且通道已耗尽的计时器上才应调用重置。”从 time.Timer.Reset 文档开始。
-
@Peter,我相信这实际上是一个很好的近似值。的真实代码。实际上,您目前必须在调用
cancel()后继续读取chan,否则写入它的goroutine 可能 阻塞并且永远不会退出。顺便说一句,我宁愿在取消后不必阅读 chan,这就是这个问题的重点。 -
不,goroutine 不会阻塞,因为 ctx.Done() 情况可用。