必须使用 std::chrono::high_resolution_clock::now() 测时,因其在各平台提供纳秒级稳定分辨率;避免 system_clock(时间跳变)和 steady_clock(旧编译器分辨率不足);需用 duration_cast 转换单位,不可直接调 count();单次测量不可靠,应多次取最小值或中位数;注意测量干扰与编译器优化影响。

用 std::chrono::high_resolution_clock::now() 获取时间点,别用 system_clock 或 steady_clock
直接测耗时,必须用 std::chrono::high_resolution_clock。它在 Linux/macOS 上通常映射到 CLOCK_MONOTONIC,Windows 上对应 QueryPerformanceCounter,是标准库中唯一能稳定支持纳秒级单位运算的时钟。
system_clock 会随系统时间调整跳变,steady_clock 虽单调但旧编译器(如 GCC 4.9、MSVC 2013)可能只提供毫秒级分辨率——测微秒级函数时误差可达 1000 倍。
- 始终写
auto start = std::chrono::high_resolution_clock::now();,不要省略命名空间 - 避免 typedef 别名隐藏时钟类型,比如
using clock = std::chrono::steady_clock;—— 容易误用 - 两次
now()调用之间,不要插入日志、内存分配、IO 等干扰操作,否则测量的是“带副作用的耗时”,不是纯逻辑执行时间
duration_cast 是必须步骤,不能直接调 count()
end - start 得到的是 duration 类型,但它底层的 period 不一定是纳秒——可能是微秒甚至毫秒,取决于平台和实现。直接写 (end - start).count() 拿到的是“滴答数”,不是纳秒数。
例如在某台 Windows 机器上,high_resolution_clock::period::den == 10'000'000(即 100 纳秒/滴答),此时 count() 返回值 ×100 才是真实纳秒。
立即学习“C++免费学习笔记(深入)”;
- 要纳秒:写
std::chrono::duration_cast<:chrono::nanoseconds>(end - start).count()</:chrono::nanoseconds> - 要微秒:写
std::chrono::duration_cast<:chrono::microseconds>(end - start).count()</:chrono::microseconds>,别图省事用/1000手动换算 - 避免
auto diff = end - start; long ns = diff.count();—— 这行代码在不同平台行为不一致,且无法静态检查单位
单次测量不可靠,建议取最小值或中位数
操作系统调度、CPU 频率动态调整、TLB miss、缓存预热都会让单次测量抖动很大。一个 500ns 的函数,实测可能返回 300ns~1200ns。
- 至少循环 5–10 次,记录每次
duration_cast后的整数值 - 用
std::min_element取最小值(排除调度干扰)或std::nth_element取中位数(更鲁棒) - 如果函数本身有副作用(比如修改全局状态),需在每次迭代前重置状态,否则后几次测量失真
- 对极短操作(RDTSC 指令手撸(仅限 x86-64 且关闭频率缩放),但
high_resolution_clock+ 多次取最小已覆盖 99% 场景
Windows 下老环境的 QueryPerformanceCounter 兼容性陷阱
如果你还在维护 Windows 7 + VC2013 或 MinGW-w64 旧版本,high_resolution_clock::period::den 可能固定为 10'000'000,导致 duration_cast<nanoseconds></nanoseconds> 向上取整——比如真实 105ns 会被记成 200ns。
这时手动调 QueryPerformanceCounter 反而更准,但必须检查频率:
- 先调
QueryPerformanceFrequency(&freq),确认freq.QuadPart > 0 - 再算
(end.QuadPart - start.QuadPart) * 1'000'000'000LL / freq.QuadPart,注意用LL防溢出 - 别忘了链接
winmm.lib,否则链接失败 - 新项目一律用
high_resolution_clock,手动调用只作为兜底方案
真正容易被忽略的不是怎么写,而是忘记「测量本身会改变行为」:哪怕只是加两行 now(),也可能让编译器放弃内联、打乱指令流水线。测得越准,越要怀疑它是不是你想要的那个“真实耗时”。


















