应使用 std::chrono::high_resolution_clock 测单次循环耗时,因其基于硬件计数器、精度达纳秒级且不受系统时钟调整影响;需预热5–10次并正式运行≥100次,避免冷启动与编译器优化干扰。

用 std::chrono 测单次循环耗时,别用 clock()
直接用 clock() 会受 CPU 调度、线程抢占干扰,返回的是进程累计 CPU 时间,不是真实墙钟时间。尤其在多线程或系统负载高时,结果偏差可能达毫秒级。推荐用 std::chrono::high_resolution_clock,它基于硬件计数器,精度通常在纳秒级(实际取决于平台,Linux 上常为 ~15ns)。
实操建议:
- 在循环开始前调用一次
start = std::chrono::high_resolution_clock::now(),每次迭代末尾记录end = std::chrono::high_resolution_clock::now() - 用
std::chrono::duration_cast<:chrono::nanoseconds>(end - start).count()</:chrono::nanoseconds>得到纳秒整数,避免浮点误差累积 - 别用
system_clock:它可能被系统时钟调整影响(如 NTP 同步),不适合性能测量
如何排除首次运行的冷启动干扰
第一次执行循环时,代码段、数据页、分支预测器都未预热,耗时明显偏高。不剔除会导致平均值失真,尤其当循环总次数少于 100 时更显著。
实操建议:
- 先跑 5–10 次“预热循环”,不做计时,只执行逻辑
- 再正式计时循环,建议至少 100 次以上,避免单次异常值主导均值
- 如果想更鲁棒,可对正式循环的每次耗时存入
std::vector,之后剔除最大/最小 5% 再求均值(而非简单算术平均)
注意编译器优化导致的空循环被优化掉
如果你测的是一段看似有计算但实际没副作用的循环(比如只更新局部变量),-O2 或更高优化等级下,GCC/Clang 可能直接删掉整个循环体,测出来全是 0ns。
实操建议:
- 确保循环内有可观测副作用:例如把关键计算结果写入
volatile变量,或用asm volatile("" ::: "memory")插入编译器屏障 - 更稳妥的做法是让结果参与后续输出(如
std::cout ),或把结果存入全局 <code>std::vector(但注意内存分配开销要单独扣除) - 用
objdump -d your_binary | grep -A20 your_loop_label确认汇编里循环体确实存在
跨平台时间单位转换要小心 duration_cast 截断
std::chrono::nanoseconds 转 double 微秒时,若直接除以 1000.0,可能因浮点精度丢失低三位纳秒;而用 duration_cast<:chrono::microseconds></:chrono::microseconds> 又会向下取整,丢掉余数。
实操建议:
- 统一用纳秒整数做所有中间计算,最后再转成带小数的微秒:
double us = ns_count / 1000.0 - 避免嵌套
duration_cast:比如从nanoseconds先转microseconds再转double,会损失精度 - Windows 上
high_resolution_clock实际等价于steady_clock,但某些旧 MSVC 版本(steady_clock
最易被忽略的是:循环体里哪怕一个 std::cout 或 malloc,都会让测量结果反映 I/O 或堆分配开销,而不是纯计算时间。真要测算法核心,得把外围操作剥离干净,否则“平均时间”这个数字根本没法归因。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











