关于时间的准确性。

时间:2018-07-19 06:42:13

标签: go timer

package main


import (
    "time"
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(1)
    TestTicker(wg)
    wg.Wait()
}

func TestTicker(wg sync.WaitGroup) {
    calDuration := func(duration time.Duration) time.Duration {
        now := time.Now()
        return now.Truncate(duration).Add(duration).Sub(now)
    }
    go func(){
        t := time.NewTimer(calDuration(time.Minute))
        for {
            <-t.C
            fmt.Println(time.Now())
            t.Reset(calDuration(time.Minute))
        }
        wg.Done()
    }()
}

有时会每分钟滴答两次,因为持续时间可能会缩短。真的很奇怪有人可以帮我吗。谢谢

我只是在调用TestTicker时使用waitgroup来保存主要功能。

我正在MacOS上运行测试代码

2018-07-19 14:36:00.003887996 +0800 CST m=+24.916092657
2018-07-19 14:37:00.002985076 +0800 CST m=+84.917119245
2018-07-19 14:38:00.001214551 +0800 CST m=+144.917278207
2018-07-19 14:39:00.000418561 +0800 CST m=+204.918411736
2018-07-19 14:39:59.999490194 +0800 CST m=+264.919412884
2018-07-19 14:40:00.000167519 +0800 CST m=+264.920090231
2018-07-19 14:40:59.99914446 +0800 CST m=+324.920996684
2018-07-19 14:41:00.000247228 +0800 CST m=+324.922099488

1 个答案:

答案 0 :(得分:-1)

计时器精度可能会因操作系统,硬件和CPU负载而异。虚拟机在提供准确的计时器方面似乎特别糟糕(请参见https://github.com/golang/go/issues/14410)。不幸的是,您没有提到在什么环境中运行此代码。

如果您可以忍受不准确的情况,并且仍然需要代码在整整一分钟左右做某事,则代码会中断,因为间隔太短(14:39:59.999490194仅比{{1}小500µs }),14:40将使其等待几微秒,直到下一整分钟。为了解决这个问题,您需要使用calDuration而不是Duration.Round

也不要忘记t.C返回计时器触发的时间,因此您需要在对Duration.Truncate的调用中使用此值(这还可以节省昂贵的系统调用)。

calDuration

另一种方法是使用标准库中的func TestTicker(wg *sync.WaitGroup) { calDuration := func(now time.Time, duration time.Duration) time.Duration { return now.Round(duration).Add(duration).Sub(now) } go func(){ t := time.NewTimer(calDuration(time.Now(), time.Minute)) for { now := <-t.C fmt.Println(now) t.Reset(calDuration(now, time.Minute)) } wg.Done() }() } 并在开始行情自动收录器之前发出适当的睡眠,以使其在一整分钟内进行滴答:

time.Ticker