在Go中精确测量持续时间的正确方法是什么?大多数应用程序仅使用标准时间包和以下方法:
var startTime = time.Now() doSomeHardWork() var duration = time.Since(startTime) // or: time.Now() - startTime
但是,time.Now()返回当前系统时间,这导致两个缺陷:
time.Now()
从MSDN:
[时间服务]调整本地时钟速率以使其朝着正确的时间收敛。如果本地时钟与[准确时间样本]之间的时差太大而无法通过调整本地时钟速率进行校正,则时间服务会将本地时钟设置为正确的时间。
如果系统时间更改(手动更改或由于DST更改),则有可能检测到无效的持续时间并将其丢弃。但是,如果系统时钟的滴答声加快了例如10%以与世界时间同步,则实际上是不可能检测到的。这是预期的行为以及系统时钟的设计方式。
因此,大多数其他语言都提供了专用的API来测量持续时间:
System.nanoTime()
System.currentTimeMillis()
System.Diagnostics.Stopwatch
QueryPerformanceCounter
QueryPerformanceFrequency
std::chrono::steady_clock
std::chrono::high_resolution_clock
is_steady
true
performance.now()
new Date()
在Go中精确测量执行时间的正确方法是什么?
包装时间 单调时钟 操作系统同时提供“挂钟”和“单调时钟”,“挂钟”会随时钟同步的变化而变化。一般规则是壁钟用于指示时间,单调时钟用于测量时间。在该程序包中,不是拆分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),对挂钟重置也同样有效。
包装时间
单调时钟
操作系统同时提供“挂钟”和“单调时钟”,“挂钟”会随时钟同步的变化而变化。一般规则是壁钟用于指示时间,单调时钟用于测量时间。在该程序包中,不是拆分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中的单调经过时间测量。