2 回答
TA贡献1874条经验 获得超12个赞
例如,假设程序尚未从 tC 接收到:
if !t.Stop() {
<-t.C
}
这不能与来自计时器通道的其他接收同时完成。
有人可能会说这不是一个很好的例子,因为它假设计时器在您调用时正在运行t.Stop
。但它确实继续提到,如果已经有一些现有的 Goroutine 正在或可能正在读取t.C
.
(Reset
文档重复了所有这些,并且顺序有点错误,因为Reset
排序在 之前Stop
。)
本质上,整个地区都有点令人担忧。没有好的通用答案,因为在返回t.Stop
呼叫期间至少存在三种可能的情况:
没有人正在收听该频道,并且频道中现在没有定时器滴答声。如果计时器在调用之前
t.Stop
已停止,通常会出现这种情况。如果计时器已经停止,t.Stop
则始终返回 false。没有人正在收听该频道,并且频道中现在有计时器滴答声。当计时器正在运行但
t.Stop
无法阻止其触发时,总是会出现这种情况。在这种情况下,t.Stop
返回 false。当计时器正在运行但在您调用之前t.Stop
就触发了,因此它自己停止了,所以t.Stop
无法停止它并返回 false。其他人正在收听该频道。
在最后一种情况下,您不应该执行任何操作。在第一种情况下,您不应该执行任何操作。在第二种情况下,您可能希望从通道接收以便将其清除。这就是他们的例子的目的。
有人可能会争辩说:
if !t.Stop() {
select {
case <-t.C:
default:
}
}
是一个更好的例子。它执行一次非阻塞尝试,该尝试将消耗计时器滴答(如果存在),如果没有计时器滴答,则不执行任何操作。无论您调用 时计时器是否实际运行,这都有效t.Stop。事实上,如果t.Stopreturns ,它甚至可以工作true,尽管在这种情况下,t.Stop停止了计时器,因此计时器从未设法将计时器滴答放入通道中。(因此,如果通道中存在数据,则它必然是先前清除通道失败所遗留的。如果不存在此类错误,则尝试接收也就不必要了。)
但是,如果其他人(其他一些 goroutine)正在或可能正在读取该通道,那么您根本不应该执行此操作。尽管调用了 ,但无法知道谁(您或他们)将获得通道中可能存在的任何计时器滴答声Stop。
同时,如果您不打算进一步使用计时器,那么在通道中留下一个计时器滴答声(如果有的话)相对无害。当通道本身被垃圾收集时,它也会被垃圾收集。当然,这是否明智取决于您对计时器所做的事情,但在这些情况下,只需调用t.Stop并忽略其返回值就足够了。
TA贡献1951条经验 获得超3个赞
您创建一个计时器并立即停止它:
var tmr = time.NewTimer(time.Second) tmr.Stop()
这没有任何意义,我认为这只是你的“意外”。
但更进一步,在循环内部:
case _, ok := <-watcher.Events:
当发生这种情况时,您声称这不起作用:
if !tmr.Stop() { fmt.Println(`Ticker: CHAN DRAIN`) <-tmr.C // STOPS HERE AND GOES NO FURTHER }
Timer.Stop()
记录true
如果此调用停止计时器以及false
计时器已停止(或到期)则返回。但是你的计时器在创建后就已经停止了,所以正确tmr.Stop()
返回false
,所以你进入if
并尝试从 接收tmr.C
,但由于计时器“长时间”停止,因此不会在其通道上发送任何内容,因此这是一个阻塞(永远)操作。
如果您是使用 显式停止计时器的人timer.Stop()
,则推荐的用于耗尽其通道的“模式”没有任何意义,并且不适用于第二次调用Timer.Stop()
。
- 2 回答
- 0 关注
- 307 浏览
添加回答
举报