【发布时间】:2017-08-21 07:13:37
【问题描述】:
在 Go 中精确测量持续时间的正确方法是什么? 大多数应用程序只是使用标准时间包和以下方法:
var startTime = time.Now()
doSomeHardWork()
var duration = time.Since(startTime) // or: time.Now() - startTime
但是time.Now()返回的是当前系统时间,这会导致两个缺陷:
- 如果系统时间在测量过程中发生变化(例如,由于时区变化 (DST) 或闰秒),则生成的持续时间也是错误的.
-
系统时间可以故意比实际时间更快或更慢。当操作系统将内部时钟与 NTP 时间服务器同步时,总是会发生这种情况(每小时可能会发生几次!)
来自MSDN:
[时间服务] 调整本地时钟频率以使其能够 收敛到正确的时间。如果两者之间的时间差 本地时钟和 [accurate time sample] 太大而无法更正 调整本地时钟速率,时间服务设置本地时钟 到正确的时间。
如果系统时间更改(手动或由于 DST),可能会检测到无效的持续时间并将其丢弃。但是如果系统时钟滴答作响,例如与世界时间同步速度快 10%,几乎无法检测到。这是预期的行为以及系统时钟的设计方式。
因此,大多数其他语言都提供专用 API 来测量持续时间:
- Java 有
System.nanoTime(),System.currentTimeMillis()将等同于time.Now()并且是错误的 - C# 有
System.Diagnostics.Stopwatch - Windows 上的 C/C++ 有
QueryPerformanceCounter和QueryPerformanceFrequency - C++11 及更高版本有
std::chrono::steady_clock,或std::chrono::high_resolution_clock当其is_steady成员常量为true时 - JavaScript有
performance.now(),而new Date()的使用是错误的
在 Go 中精确测量执行时间的正确方法是什么?
【问题讨论】:
-
从技术上讲,
performance.now()是一种 DOM 功能,而不是 JavaScript。如果您正在运行 JS,例如在服务器上,您将拥有一些其他 API。 -
如果您尝试分析某些代码的性能,使用 CPU 性能计数器来测量核心时钟周期的时间而不是挂钟时间通常很有用,因此 CPU 频率缩放可以差异较小。 (如果它受 CPU 限制,而不是内存限制(因为内存频率通常保持恒定),并且绝对不受 I/O 限制,这是有意义的。)性能计数器还可以帮助您找到 为什么 它需要时间,例如缓存未命中 vs. 分支错误预测 vs. 高延迟长依赖链 vs. 实际最大化 CPU 前端或执行单元吞吐量。
-
例如在 Linux 上
perf record ./a.out,然后是perf report。