在Go

时间:2017-08-21 07:13:38

标签: go time

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

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

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

  1. 如果在测量过程中更改了系统时间(例如由于时区更改(DST)或闰秒),则生成的持续时间也会出错
  2. 系统时间可以比实时更快或更慢地打勾。这种情况总是发生在操作系统将内部时钟与NTP时间服务器同步时(可能每小时发生几次!)

    来自MSDN

      

    [时间服务]调整本地时钟速率以允许它   收敛到正确的时间。如果之间的时差   本地时钟和[准确时间样本]太大而无法纠正   调整本地时钟速率,时间服务设置本地时钟   到了正确的时间。

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

    出于这个原因,大多数其他语言提供了用于测量持续时间的专用API:

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

3 个答案:

答案 0 :(得分:27)

  

Package time

     

单调时钟

     

操作系统提供“挂钟”,这是受制于的   时钟同步的变化,以及“单调时钟”   不。一般规则是挂钟用于告诉时间和   单调时钟用于测量时间。而不是拆分API,   在这个包中Time by time.Now包含一个墙   时钟读数和单调时钟读数;后来说实话   操作使用挂钟读数,但稍后进行时间测量   操作,特别是比较和减法,使用   单调时钟阅读。

     

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

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

其他成语,例如time.Since(start),time.Until(截止日期),以及   time.Now()。之前(截止日期),对壁钟同样强大   复位。

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

请参阅Proposal: Monotonic Elapsed Time Measurements in Go

答案 1 :(得分:6)

这可以在Go 1.9(2017年8月)中使用单调时钟,您无需做任何特别的事情就可以从中受益:

https://tip.golang.org/pkg/time/#hdr-Monotonic_Clocks

  

操作系统提供“挂钟”,这是受制于的   时钟同步的变化,以及“单调时钟”   不。一般规则是挂钟用于告诉时间和   单调时钟用于测量时间。而不是拆分API,   在这个包中Time by time.Now包含一个墙   时钟读数和单调时钟读数;后来说实话   操作使用挂钟读数,但稍后进行时间测量   操作,特别是比较和减法,使用   单调时钟阅读。

     

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

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

其他成语,例如time.Since(start),time.Until(截止日期),以及   time.Now()。之前(截止日期),对壁钟同样强大   复位。

time pkg的更改由此issue触发,这促使此proposal更改为来自Russ Cox:

  

按时间观察的时间的比较和减法。现在可以返回   如果在两者之间重置系统挂钟,则结果不正确   观察结果。我们建议将time.Time表示扩展到   保持额外的单调时钟读数用于那些   计算。除了其他好处之外,这应该是不可能的   使用time.Now和time.Since的基本经过时间测量   报告负面持续时间或其他不以现实为基础的结果。

答案 2 :(得分:5)

对于Go 1.8及之前,正确的计时功能不在时间包内,而是在runtime package中:

func nanotime() int64

为了正确测量执行时间,应使用以下程序:

var startTime = runtime.nanotime()
doSomeHardWork()
var duration = runtime.nanotime() - startTime

不幸的是,该方法本身没有很好地记录。它在this issue之后出现在long discussion if it was really neccessary。 对于Go 1.9及更新版本,请参阅Kenny Grant的答案。