【问题标题】:How do I close the timer channel?如何关闭定时器通道?
【发布时间】:2017-12-05 17:45:46
【问题描述】:

我有一个计时器,它会被某些事件重置。 go 函数使用范围监听通道。如何关闭通道以便 for 循环退出?

func resetTimer(){
        if rf.electionTimer != nil {
             rf.electionTimer.Stop()
        }
}

rf.electionTimer = time.NewTimer(electionTime) 


for _ = range rf.electionTimer.C {
  // Do something
}

【问题讨论】:

  • time.Timer 只会触发一次,因此实际上不需要覆盖它。您的意思是使用 time.Ticker 吗?
  • 我正在使用随机间隔并使用定时器重置作为 hobbs 提到的。

标签: go


【解决方案1】:

当循环应该退出时,使用通道发出信号。

rf.done := make(chan struct{})
rf.electionTimer = time.NewTimer(electionTime) 

func stopTimer(){
    if rf.electionTimer != nil {
         rf.electionTimer.Stop()
         close(rf.done)
    }
}

在循环中同时选择信号通道和定时器通道。信号通道关闭时跳出循环。

loop:
    for {
        select {
        case t := <-rf.electionTimer.C:
            // Do something
        case <-rf.done:
            break loop
        }
    }

请注意,如果应用程序未在计时器上调用Reset,则在问题或此答案中使用循环是没有意义的。如果定时器没有重置,那么只有一个值会被发送到定时器的通道。

【讨论】:

  • 将 rf.done 替换为简单的 bool 而不是 chan struct{} 可能会更有效,也更有意义。
  • @Acidic 这会在另一个 goroutine 调用 Stop 和 Reset 时引入数据竞争。
  • 谢谢,Cerise Limon。我正在重置计时器。我尝试了类似于您所写的内容,但我使用了 bool 类型的通道,当我尝试 rf.done
  • @2ank3th 发送到频道可以,但如果没有看到更多代码,我无法确定为什么它对您不起作用。
【解决方案2】:

来自timer 的频道多次没有输出时间。它只会在计时器结束后输出一次时间。因此,在for 循环中使用rf.electionTimer 是没有用的。

尝试将 for 循环替换为:

t := <-rf.electionTimer.C
// Do something with t

这将暂停执行,直到计时器停止。

请记住,使用 rf.electionTimer.Stop() 将阻止计时器永远结束并且您的 &lt;-rf.electionTimer.C 行将冻结。

如何关闭通道以退出 for 循环?

为了防止&lt;-rf.electionTimer.C阻止代码执行,建议你使用:

rf.electionTimer.Reset(0)

【讨论】:

  • 我最初的解决方案是使用 t :=
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-17
  • 2021-04-23
  • 2015-09-11
  • 2015-10-08
  • 2015-02-19
  • 1970-01-01
相关资源
最近更新 更多