我在 goroutine 中有一个空闲超时计时器select,如果我看到活动,我想取消计时器。
我查看了文档,但我不确定我是否清楚它所说的内容。
func (t *Timer) Stop() bool
停止可防止定时器触发。如果调用停止计时器,则返回 true,如果计时器已过期或已停止,则返回 false。停止不会关闭通道,以防止从通道读取不正确地成功。要防止使用 NewTimer 创建的计时器在调用 Stop 后触发,请检查返回值并排空通道。例如,假设程序尚未从 tC 收到:
if !t.Stop() { <-t.C }这不能与来自定时器通道的其他接收同时进行。
我试图了解何时必须手动排空通道。
我会列出我的理解,如果我错了,请纠正我。
如果Stop返回,false这意味着:
在我的情况下,从计时器获得多余的事件没什么大不了的,这是否告诉我应该在这里做什么?
您可能需要排空通道的原因是 goroutine 的调度方式。
问题
想象一下这个案例:
t.Ct.Stop()已被调用。在这种情况下, channel 上有一个值t.C,并t.Stop()返回 false 因为“计时器已经过期”(即当它在 上发送值时t.C)。
文档说“这不能与其他接收同时进行”的原因是因为不能保证if !t.Stop {和<-t.C. stop 命令可能返回 false,进入 if 主体。然后可以调度另一个 goroutine 并从t.Cif 语句的主体试图排出的值中读取值。这将导致数据争用并导致 if 语句内的阻塞。(正如您在问题中指出的那样!)
解决方案
这取决于监听计时器的事物的行为是什么。
如果你只是在一个简单的选择中:
select {
case result <- doWork():
case <-t.C
}
Run Code Online (Sandbox Code Playgroud)
类似上面的东西。可能会发生以下几种情况之一:
doWork,发送结果,一切都很好。doWork()完成。t.Stop(),但为时已晚,因为值已发送,导致超时,中断选择。只要你对case 4没问题,调用后不需要交互/drain channel Stop.
如果您对案例 4t.C不满意。您仍然无法排空通道,因为还有另一个 goroutine 在监听它。这可能会阻塞 if 语句。相反,您必须找到另一种方式来布置代码,或者确保选择中的 goroutine 不会仍在侦听通道。
| 归档时间: |
|
| 查看次数: |
746 次 |
| 最近记录: |