std::chrono::high_resolution_clock 并非总是纳秒级,实际精度需运行时检查分母;应测代码块而非单次调用,避免在循环内频繁调用 now() 以防止测量污染。

std::chrono::high_resolution_clock 真的够高吗?
多数场景下,std::chrono::high_resolution_clock 是最接近硬件精度的时钟,但它在不同平台语义不同:Windows 上通常映射到 QueryPerformanceCounter(纳秒级),Linux 上常为 CLOCK_MONOTONIC(微秒或纳秒,取决于内核配置)。不能假设它一定返回纳秒——实际精度需运行时检查:
auto res = std::chrono::high_resolution_clock::period::den; // 分母,如 1000000000 表示纳秒若结果是
1000000,说明底层只支持微秒。更稳妥的做法是统一用 std::chrono::nanoseconds 存储差值,让系统自动做精度截断或舍入。
如何避免测量误差:别在循环里反复调用 now()
频繁调用 now() 本身有开销,尤其在 tight loop 中会污染测量结果。正确做法是「测一段代码块」,而非「测单次函数调用」:
- 用
auto start = std::chrono::high_resolution_clock::now();记录起点 - 执行待测逻辑(确保编译器不优化掉,必要时加
volatile或用结果) - 再调用一次
now()得终点,相减得duration - 避免把
now()放进被测循环内部——那测的是时钟开销,不是你的算法
例如,错误写法:
for (int i = 0; i < N; ++i) {
auto t = std::chrono::high_resolution_clock::now(); // ❌ 每次都调用
do_work();
}正确写法:auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < N; ++i) {
do_work();
}
auto end = std::chrono::high_resolution_clock::now(); // ✅ 只调两次
duration_cast 的陷阱:向下取整 vs 四舍五入
std::chrono::duration_cast 默认向零截断(即向下取整),比如 1234 ns 转成 std::chrono::microseconds 得到 1 μs,不是 1.234。若需要更准的浮点表示,应先转为 double 基础单位:
- 要整数微秒:用
duration_cast<:chrono::microseconds>(end - start).count()</:chrono::microseconds> - 要带小数的毫秒:用
std::chrono::duration<double std::milli>(end - start).count()</double> - 避免链式 cast:
duration_cast<ms>(duration_cast<ns>(d))</ns></ms>会多一次截断,直接 cast 到目标类型即可
常见误用:
auto d = end - start; auto us = std::chrono::duration_cast<std::chrono::microseconds>(d).count(); // 截断后整数 auto us_f = std::chrono::duration<double, std::micro>(d).count(); // 保留小数,如 1234.567
跨线程 / 多核时要注意 clock 稳定性
high_resolution_clock 在某些老 CPU 或 BIOS 设置下可能受频率缩放影响(如 Intel SpeedStep),导致同一段代码在不同核心上测出差异较大的时间。若需严格可重现的性能数据:
立即学习“C++免费学习笔记(深入)”;
- 优先用
std::chrono::steady_clock(单调、不受系统时间调整影响,但精度可能略低) - Linux 下可绑定进程到固定 CPU 核并禁用节能:
taskset -c 0 ./bench && echo performance | sudo tee /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor - Windows 上建议关闭「快速启动」和「连接待机」,并在电源选项中设为「高性能」
真正难搞的不是写对代码,而是让硬件别偷偷降频——很多“性能波动”问题根源在此。











