在Go中精确测量持续时间的正确方法是什么?大多数应用程序只使用标准时间包和以下方法:
var startTime = time.Now()
doSomeHardWork()
var duration = time.Since(startTime) // or: time.Now() - startTime
Run Code Online (Sandbox Code Playgroud)
但是,time.Now()返回当前系统时间,这会导致两个缺陷:
系统时间可以比实时更快或更慢地打勾.当操作系统将内部时钟与NTP时间服务器同步时(这可能每小时发生几次!),这种情况总会发生.
来自MSDN:
[时间服务]调整本地时钟速率,使其收敛到正确的时间.如果本地时钟和[准确时间样本]之间的时间差太大而无法通过调整本地时钟速率来校正,则时间服务将本地时钟设置为正确的时间.
如果系统时间更改(手动或由于DST),则可能会检测到无效持续时间并将其丢弃.但是,如果系统时钟速度比世界时间快10%,则几乎不可能检测到.这是预期的行为以及系统时钟的设计方式.
因此,大多数其他语言都提供了用于测量持续时间的专用API:
System.nanoTime(),System.currentTimeMillis()等同于time.Now()错误System.Diagnostics.StopwatchQueryPerformanceCounter和QueryPerformanceFrequencystd::chrono::steady_clock,或std::chrono::high_resolution_clock当它的is_steady构件是恒定trueperformance.now(),虽然使用new Date()是错误的在Go中精确测量执行时间的正确方法是什么?
pet*_*rSO 27
单调时钟
操作系统既提供"挂钟",也可以改变时钟同步,而"单调时钟"则不然.一般规则是挂钟用于告知时间,单调时钟用于测量时间.而不是拆分API,在这个包中Time by Time.Now包含挂钟读数和单调时钟读数; 后来的时间操作使用挂钟读数,但后来的时间测量操作,特别是比较和减法,使用单调时钟读数.
例如,即使在定时操作期间更改挂钟,此代码也始终计算大约20毫秒的正经过时间:
Run Code Online (Sandbox Code Playgroud)start := time.Now() ... operation that takes 20 milliseconds ... t := time.Now() elapsed := t.Sub(start)其他成语,例如time.Since(start),time.Until(截止日期)和time.Now().Before(截止日期),对于挂钟重置同样强大.
从Go 1.9开始(2017年8月24日发布),Go使用单调时钟作为持续时间.
请参阅提案:Go中的单调经过时间测量.
这是在带有单调时钟的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)
Run Code Online (Sandbox Code Playgroud)
其他成语,例如time.Since(start),time.Until(截止日期)和time.Now().Before(截止日期),对于挂钟重置同样强大.
此问题触发了pkg 时间的这一变化,这促使此提议从Russ Cox进行更改:
比较和减去时间观察到的时间.如果在两个观察值之间重置系统挂钟,则现在可能返回不正确的结果.我们建议延长time.Time表示以保持额外的单调时钟读数以用于那些计算.除了其他好处之外,这应该使得基本的经过时间测量不可能使用time.Now和time.Since报告负面持续时间或其他不基于现实的结果.
对于Go 1.8及之前,正确的计时功能不在时间包内,而是在运行时包中:
func nanotime() int64
Run Code Online (Sandbox Code Playgroud)
为了正确测量执行时间,应使用以下过程:
var startTime = runtime.nanotime()
doSomeHardWork()
var duration = runtime.nanotime() - startTime
Run Code Online (Sandbox Code Playgroud)
不幸的是,该方法本身没有很好地记录.经过长时间的讨论后,它出现在这个问题上,如果它真的是必要的话.对于Go 1.9及更新版本,请参阅Kenny Grant的回答.
| 归档时间: |
|
| 查看次数: |
6198 次 |
| 最近记录: |