一尘不染

在Go中正确测量持续时间

go

在Go中精确测量持续时间的正确方法是什么?大多数应用程序仅使用标准时间包和以下方法:

var startTime = time.Now()
doSomeHardWork()
var duration = time.Since(startTime) // or: time.Now() - startTime

但是,time.Now()返回当前系统时间,这导致两个缺陷:

  1. 如果在测量过程中更改了系统时间(例如,由于 时区更改 (DST)或 leap秒 ),则所产生的持续时间也是错误的。
  2. 系统时间可能故意比实时时间变慢或变慢。当操作系统将内部时钟与NTP时间服务器同步时,通常会发生这种情况(每小时可能发生几次!)

MSDN

[时间服务]调整本地时钟速率以使其朝着正确的时间收敛。如果本地时钟与[准确时间样本]之间的时差太大而无法通过调整本地时钟速率进行校正,则时间服务会将本地时钟设置为正确的时间。

如果系统时间更改(手动更改或由于DST更改),则有可能检测到无效的持续时间并将其丢弃。但是,如果系统时钟的滴答声加快了例如10%以与世界时间同步,则实际上是不可能检测到的。这是预期的行为以及系统时钟的设计方式。

因此,大多数其他语言都提供了专用的API来测量持续时间:

在Go中精确测量执行时间的正确方法是什么?


阅读 284

收藏
2020-07-02

共1个答案

一尘不染

包装时间

单调时钟

操作系统同时提供“挂钟”和“单调时钟”,“挂钟”会随时钟同步的变化而变化。一般规则是壁钟用于指示时间,单调时钟用于测量时间。在该程序包中,不是拆分API,而是按时间返回时间。现在,它既包含挂钟读数又包含单调时钟读数。以后的计时操作将使用挂钟读数,但以后的时间测量操作(特别是比较和减法)将使用单调时钟读数。

例如,即使在计时操作期间更改了挂钟,此代码也始终会计算约20毫秒的正经过时间:

start := time.Now()
... operation that takes 20 milliseconds ...
t := time.Now()
elapsed := t.Sub(start)

类似的其他用法,例如time.Since(start),time.Until(deadline)和time.Now()。Before(deadline),对挂钟重置也同样有效。

从Go 1.9(发布于2017年8月24日)开始,Go在持续时间内使用单调时钟。

请参阅提案:Go中的单调经过时间测量

2020-07-02