【问题标题】:Best way to instantly restart a goroutine?立即重新启动 goroutine 的最佳方法?
【发布时间】:2022-01-15 09:33:47
【问题描述】:

我写了以下函数:

func (timer *Timer) ticker() {
    for timer.time >= 0 {
        select {
        case <-timer.stopFlag:
            return
        default:
            timer.DataChannel <- timer.timeToString()
            timer.time--
            time.Sleep(time.Second)
        }
    }
}
func startLabelUpdateListener(timer *t.Timer, w *app.Window, label *string) {
    for time := range timer.DataChannel {
        *label = time
        w.Invalidate()
    }
}

这是一个简单的计时器,它连接到一个标签,每当 DataChanel 上有更新时,该标签就会更新。它们都被称为 goroutine。

现在有没有一种方法可以立即停止自动收报机并在之后再次调用它?假设我想重新启动这个计时器。我希望它立即停止,并启动另一个ticker goroutine 来接管。

我尝试了以下方法,但遇到了一些问题:

timer.stopFlag <- true
go timer.ticker()
...

问题在于它不是即时的,因为我正在使用 time.Sleep() go 一直等到睡眠结束,这对于响应性不好,因为这会引入 UI 延迟。使用dataChannel &lt;- "some_time" 之类的内容手动更新标签意味着如果用户在 0.9 秒睡眠后单击重启按钮,则计时器在 1.9 秒内不会改变。

close(timer.stopFlag)
timer.stopFlag = make(chan bool)
go timer.ticker()
...

这很好而且即时(通过睡眠或至少看起来是这样)但问题是,通道现在已关闭并重新打开它以某种方式阻止前一个 goroutine 终止并按下重新启动按钮几次堆叠协程

我还考虑过将 time.sleep 设置为 0.1 秒,并且每 10 次迭代减少一次时间,但这感觉有点笨拙。 有没有更好的解决方案?

【问题讨论】:

    标签: go


    【解决方案1】:

    使用time.Ticker 而不是睡觉。

    func (timer *Timer) ticker() {
        // Send the first.
        timer.DataChannel <- timer.timeToString()
        timer.time--
    
        // Loop sending each second. 
        t := time.NewTicker(time.Second)
        defer t.Stop()
        for timer.time >= 0 {
            select {
            case <-timer.stopFlag:
                return
            case <-t.C:
                timer.DataChannel <- timer.timeToString()
                timer.time--
            }
        }
    }
    

    【讨论】:

    • 这看起来像我要找的东西!但是我遇到了一个问题,计时器只升起了 C 标志一次,这意味着它只减少了 1 秒并停止了。我通过在 case
    • 糟糕,我打错了。使用 Ticker,而不是 Timer。请参阅编辑以回答。
    • 哇,效果很好,谢谢!
    猜你喜欢
    • 2022-07-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-05
    • 1970-01-01
    • 2012-07-10
    • 1970-01-01
    相关资源
    最近更新 更多