dtf76989 2018-07-19 06:42
浏览 194

关于时间的准确性。

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()
    }()
}

It sometimes happens to tick twice a minute as the duration may shrink. It's really strange. Could somebody help me. Thanks

I simply use waitgroup to hold the main function while calling TestTicker.

I'm running the test code on my 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条回答 默认 最新

  • dreamwind1985 2018-07-19 13:58
    关注

    The timer accuracy can vary depending on your OS, hardware and CPU load. Virtual Machines seem particularly bad at providing accurate timers (see https://github.com/golang/go/issues/14410). Unfortunately, you do not mention in what environment you're running this code.

    If you can live with the inaccuracies, and still need your code do do something at about a full minute, your code breaks because when the interval is too short (14:39:59.999490194 is only 500µs short of 14:40), calDuration will make it wait that few microseconds until the next full minute. In order to fix this you need to use Duration.Round instead of Duration.Truncate.

    Also do not forget that t.C returns the time at which the timer fired, so you need to use this value in your call to calDuration (this also saves you a costly syscalls).

    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()
        }()
    }
    

    Another approach is to use time.Ticker from the standard library and issue an appropriate sleep before starting the ticker so that it ticks on a full minute:

    func TestTicker(wg *sync.WaitGroup) {
        go func(interval time.Duration) {
            // wait until next time interval
            now := time.Now()
            time.Sleep(now.Truncate(interval).Add(interval).Sub(now))
            // get time of first beat
            now = time.Now()
            // start the ticker
            t := time.NewTicker(interval)
            for {
                fmt.Println(now)
                now = <-t.C
            }
            wg.Done()
        }(time.Minute)
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 一直显示正在等待HID—ISP
  • ¥15 Python turtle 画图