std::chrono::high_resolution_clock是测单次耗时最稳的选择,它在主流平台映射到最高精度计时源,但需注意其不保证跨核/长时间单调性,且测量的是挂钟时间而非CPU时间。

用 std::chrono::high_resolution_clock 测单次耗时最稳
绝大多数场景下,std::chrono::high_resolution_clock 是唯一该选的时钟——它在主流平台(Linux/Windows/macOS)都映射到系统最高精度计时源,比如 CLOCK_MONOTONIC 或 QueryPerformanceCounter。别碰 system_clock,它可能受系统时间调整干扰;也别信 steady_clock 在某些旧编译器(如 GCC 4.8)上其实是 system_clock 的别名。
实操建议:
- 用
time_point记录起点和终点,别用duration_cast提前转成毫秒或秒——中间计算保留纳秒精度,最后再转,避免累积舍入误差 - 避免在循环内反复调用
now()测微小操作:函数调用开销本身可能接近被测代码耗时,导致结果失真 - 示例:
auto start = std::chrono::high_resolution_clock::now();<br>do_something();<br>auto end = std::chrono::high_resolution_clock::now();<br>auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
测多次运行取平均?小心编译器优化把代码“优化”没了
想测一个函数执行 1000 次的平均耗时,直接写循环容易被编译器识别为无副作用而整个删掉,或者把循环展开+常量传播,最终测的不是你想要的逻辑。
常见错误现象:ns 输出恒为 0 或极小值(如 1–10 纳秒),且多次运行结果高度一致。
立即学习“C++免费学习笔记(深入)”;
实操建议:
- 把被测函数的输出(哪怕只是计算结果)强制“逃逸”出作用域:用
volatile变量接收,或传给asm volatile("" ::: "memory")做内存屏障 - 关闭特定优化:测试时加
-O0,但注意这会掩盖真实性能瓶颈;更合理的是用-O2+ 手动防优化 - 别只跑一次:用
std::chrono::duration累加每次耗时,最后除以次数,避免浮点除法引入额外误差
std::chrono::duration_cast 截断不四舍五入,整数除法陷阱要手算
duration_cast 对所有向下转换(比如从 nanoseconds 转 milliseconds)一律截断,不是四舍五入。这意味着 999999 纳秒会被转成 0 毫秒,而不是 1 毫秒。
使用场景:当你需要“向上取整毫秒”或“保留小数位显示”,不能依赖 duration_cast 一步到位。
实操建议:
- 需要向上取整:先加偏移再截断,例如
(ns + 999999) / 1000000得毫秒数(整数运算) - 需要保留两位小数毫秒:转成
double计算,double ms = ns.count() / 1e6;,但注意double对超大纳秒值会丢失精度 - 参数差异:
duration_cast模板参数是目标类型,不是单位字符串,别写成duration_cast<"ms">这种非法语法
跨线程或长周期测量?high_resolution_clock 不一定单调
标准只要求 high_resolution_clock “尽可能高精度”,没保证跨核/跨线程/长时间运行下的单调性。实际中,在某些 ARM 平台或虚拟机里,不同 CPU 核心读到的 now() 可能有几十纳秒偏差;持续运行几小时后,也可能因硬件计数器溢出或系统校准出现跳变。
性能 / 兼容性影响:对微秒级敏感的实时系统或分布式追踪,这种偏差不可忽略。
实操建议:
- 单线程短时测量(high_resolution_clock
- 跨线程比对时间戳:改用
std::chrono::steady_clock(它明确要求单调),哪怕精度略低 - 超长周期(>1 小时):定期与
system_clock同步校准,或改用 OS 原生 API(如 Linux 的clock_gettime(CLOCK_MONOTONIC_RAW))
真正难的不是调哪个函数,而是搞清你测的到底是“CPU 时间”“挂钟时间”还是“调度等待时间”——chrono 给你的永远是挂钟时间,如果函数里混了 sleep、锁竞争或 IO 等待,测出来就是它们的总和,不是纯计算耗时。










