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
最佳答案
计时器的准确度可能因您的操作系统、硬件和 CPU 负载而异。虚拟机似乎特别不擅长提供准确的计时器(参见 https://github.com/golang/go/issues/14410)。不幸的是,您没有提到您在什么环境中运行此代码。
如果您可以忍受这些不准确,并且仍然需要您的代码在整整一分钟内做一些事情,您的代码就会中断,因为当间隔太短时(14:39:59.999490194
仅比 14:40
短 500µs,calDuration
将使其等待几微秒,直到下一个整分钟。为了解决这个问题,您需要使用 Duration.Round
而不是 Duration.Truncate
。
另外不要忘记 t.C 会返回计时器触发的时间,因此您需要在调用 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
并在启动自动收报机之前发出适当的 sleep ,以便它在一整分钟内计时:
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)
}
关于go - 关于时间的准确性.Timer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51415965/