go - 如何停止当前正在另一个 go-routine 中收听的 time.Timer?

标签 go timer

我有一个空闲超时计时器为select在 goroutine 中运行,如果我看到事件我想取消计时器。

我看过the documentation我不确定我是否清楚它说的是什么。

func (t *Timer) Stop() bool
Stop prevents the Timer from firing. It returns true if the call stops the timer, false if the timer has already expired or been stopped. Stop does not close the channel, to prevent a read from the channel succeeding incorrectly.

To prevent a timer created with NewTimer from firing after a call to Stop, check the return value and drain the channel. For example, assuming the program has not received from t.C already:

if !t.Stop() { <-t.C }

This cannot be done concurrent to other receives from the Timer's channel.

我试图了解何时必须手动排空 channel 。

我会列出我的理解,如果我错了请指正。

如果Stop返回 false这意味着:

  • 计时器已经停止
    • 在这种情况下,从 channel 读取会阻塞,所以我不应该这样做
  • 计时器已经过期
    • 因为我有另一个 goroutine 在 channel 上监听,我能确定它是否收到了事件吗?
    • 从文档的“这不能与其他接收同时完成”部分来看,这似乎不是一个选项,那么我应该怎么做?

在我的例子中,从计时器获得一个多余的事件没什么大不了的,这是否告诉我在这里应该做什么?

最佳答案

您可能需要排空 channel 的原因是 goroutine 的调度方式。

问题

想象一下这种情况:

  1. 创建了一个计时器
  2. 计时器启动,发送一个值到t.C
  3. 尚未收到/读取该值,但是 t.Stop()被称为。

在这种情况下, channel 上有一个值 t.C , 和 t.Stop()返回 false 因为“计时器已经过期”(即当它在 t.C 上发送值时)。

文档说“这不能与其他接收同时完成”的原因是因为不能保证 if !t.Stop { 之间的顺序。和 <-t.C .停止命令可以返回 false,进入 if 主体。然后可以安排另一个 goroutine 并从 t.C 中读取值if 语句的主体正试图耗尽。这会导致数据争用并导致 if 语句内部阻塞。 (正如您在问题中指出的那样!)

解决方案

这取决于监听定时器的东西的行为是什么。

如果只是简单的选择:

select {
    case result <- doWork():
    case <-t.C
}

类似上面的内容。可能会发生以下情况之一:

  1. 这项工作可以在 doWork 完成, 发送结果,一切都很好。
  2. 计时器可能会触发,导致超时,中断选择。
  3. 调用停止,停止计时器,选择的唯一出路是doWork()完成。
  4. 计时器可以触发,另一个例程调用t.Stop() , 但也太 迟到是因为值已经发送,导致超时,breaking 选择。

只要你对案例 4 没问题,你就不需要在调用 Stop. 后进行交互/排空 channel 。

如果您对案例 4 不满意。您仍然无法耗尽 t.C channel 因为有另一个 goroutine 正在监听它。这可能会阻塞 if 语句。相反,您必须找到另一种布局代码的方式,或者确保您在 select 中的 goroutine 没有仍在监听 channel 。

关于go - 如何停止当前正在另一个 go-routine 中收听的 time.Timer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51079878/

相关文章:

swift - 2 十进制定时器在 swift

c++ - 多线程崩溃

c++ - 如何使用 Boost 库创建 TimerHandler

c - Windows 上 C 语言的硬件定时器

json - 解码具有不同结构但相同键的嵌套 JSON

loops - 为什么我的 go 协程在处理后卡住了?

go - 如何通过 go-elasticsearch 包添加映射

swift - 如何在 Swift 中设置定时器

postgresql - 去 echo : POST Method gives Error "Method not allowed"

json - Go中如何自定义JSON编码输出?