std::chrono::high_resolution_clock 准确但易用错:因跨平台实现差异(如linux用clock_monotonic、windows用queryperformancecounter),其“高分辨率”不等于绝对精确,且必须用同一时钟类型采样相减,避免混用system_clock/steady_clock;测真实耗时应禁用优化、防死代码消除、取多次最小值;推荐steady_clock;duration_cast截断导致精度丢失;windows下15ms卡顿源于系统时钟粒度,默认约15.6ms。

chrono::high_resolution_clock 为什么不准
它准,但你用错了——high_resolution_clock 在不同平台底层实现不同:Linux 通常是 clock_gettime(CLOCK_MONOTONIC),Windows 可能是 QueryPerformanceCounter,但它的「高分辨率」不等于「绝对精确」,更不保证跨平台行为一致。真正的问题常出在取差值的方式上。
- 别用
system_clock或steady_clock混着比——它们时间起点和单调性保障不同,相减可能得到负值或跳变 - 必须用同一时钟类型做
time_point的两次采样再相减,例如都用steady_clock - 避免把
time_point转成time_t再算差,会丢精度、引入时区/闰秒干扰
怎么测一段代码的真实耗时(无干扰)
核心是隔离测量环境:禁用编译器优化干扰、避免缓存/分支预测预热偏差、防止编译器直接删掉空循环。
- 用
volatile或函数调用阻止死代码消除,比如do_work(); asm volatile("" ::: "rax"); - 单次测量意义不大,至少跑 3–5 次取最小值(排除系统调度抖动),别用平均值——它会被 GC、中断拖慢
- 推荐用
steady_clock:它保证单调递增且不受系统时间调整影响,适合性能测量
auto start = std::chrono::steady_clock::now(); do_work(); auto end = std::chrono::steady_clock::now(); auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
duration_cast 精度丢失的坑
duration_cast 是截断(truncation),不是四舍五入。从纳秒转毫秒时,小于 1000000 纳秒的部分直接丢弃,导致大量 sub-microsecond 操作全显示为 0ms。
- 想保留亚微秒信息?先转到
nanoseconds或用double浮点时长:std::chrono::duration<double std::nano>(end - start).count()</double> - 不要嵌套 cast,比如
duration_cast<milliseconds>(duration_cast<nanoseconds>(d))</nanoseconds></milliseconds>——中间截断两次,误差放大 - 注意
count()返回的是整型,溢出风险在大时间跨度下存在(如hours存int只撑不到 25 天)
Windows 下 chrono 高频调用偶尔卡住 15ms
这不是 chrono 的 bug,而是 Windows 默认时钟粒度问题。系统计时器默认分辨率约 15.6ms,steady_clock 在某些旧版本或电源管理模式下会受其拖累。
立即学习“C++免费学习笔记(深入)”;
- 可临时提高系统时钟精度:调用
timeBeginPeriod(1)(需winmm.lib),但会影响全局功耗,用完记得timeEndPeriod(1) - 更稳妥的做法是用
QueryPerformanceCounter手动封装,绕过 chrono 抽象层(尤其在实时性敏感场景) - 确认是否真被卡住:打印连续多次测量的差值分布,如果出现大量 0 + 少量 15–16ms 峰值,基本就是系统粒度锅
实际写基准测试时,最难控的从来不是怎么读时间,而是让被测代码真的在跑、没被优化掉、也不被其他线程抢走 CPU。chrono 本身很稳,但人容易在边界上栽跟头。









