应使用 std::chrono::high_resolution_clock 获取纳秒级时间点,两次调用 now() 计算差值并用 duration_cast 转换为毫秒;需防止编译器优化循环,可用 volatile 变量累积结果;多次测量取最小值更准确。

用 std::chrono::high_resolution_clock 获取纳秒级起点和终点
别用 clock() 或 time(),它们分辨率太低(通常是毫秒甚至更差),且受系统负载影响大。C++11 起推荐用 std::chrono,其中 std::chrono::high_resolution_clock 是实现提供的最高精度时钟(通常是纳秒级,Linux 下常为 CLOCK_MONOTONIC)。
关键点:必须用同一时钟的 now() 两次,不能混用不同时钟类型;时间差要用对应时钟的 duration 类型计算,避免隐式转换丢失精度。
- 获取起点:
auto start = std::chrono::high_resolution_clock::now(); - 执行遍历(确保编译器不优化掉,见下节)
- 获取终点:
auto end = std::chrono::high_resolution_clock::now(); - 计算毫秒:
std::chrono::duration_cast<:chrono::milliseconds>(end - start).count()</:chrono::milliseconds>
防止编译器优化掉遍历操作
如果你只写 for (auto x : arr) { /* do nothing */ },现代编译器(如 GCC -O2、Clang)大概率会直接删掉整个循环——测出来永远是 0ms。这不是测量失败,是代码被优化了。
常见可靠做法是让遍历产生“可观察副作用”,但又不影响计时逻辑本身:
立即学习“C++免费学习笔记(深入)”;
- 把结果累加到一个
volatile变量:volatile int sink = 0; for (int x : arr) sink += x; - 或用
std::accumulate并把结果赋给volatile变量(避免被内联优化) - 禁用优化仅用于测试?不现实——你要测的是真实运行性能,得在目标编译选项下测(比如 -O2)
- 注意:不要用
std::cout或文件 I/O,I/O 开销远大于遍历,会淹没你要测的信号
多次测量取最小值比取平均值更合理
单次测量受缓存预热、TLB 命中、后台进程干扰等影响极大。但“最短耗时”往往最接近纯遍历本身的开销,因为它大概率发生在 CPU 缓存已热、分支预测稳定、无中断干扰的理想窗口。
- 运行 10–100 次循环测量,记录每次
std::chrono::milliseconds的count() - 取最小值,而非平均值或中位数(平均值容易被某次突发延迟拉高)
- 如果最小值为 0,说明耗时低于时钟分辨率(比如 nanoseconds 并多跑几轮确认
- 数组要足够大(比如 ≥ 1MB),否则测量值可能被时钟误差主导
Windows 下要注意 high_resolution_clock 的实际行为
MSVC 和 MinGW 在 Windows 上对 std::chrono::high_resolution_clock 的实现不一致:MSVC 早期版本将其映射为 QueryPerformanceCounter(好),但某些旧系统或虚拟机上仍可能回落为低精度时钟。
- 运行前先验证分辨率:
auto res = std::chrono::high_resolution_clock::period::den / std::chrono::high_resolution_clock::period::num;—— 若结果是 1000000,说明是微秒级;1000000000 才是纳秒级 - 更稳妥的做法是直接用
std::chrono::steady_clock(单调、稳定,Windows 上也基于 QPC),它不保证“最高”分辨率,但保证可用且适合间隔测量 - 避免用
system_clock,它反映墙上时间,可能因 NTP 调整跳变
多次测量时最容易被忽略的是数组内存布局和 CPU 缓存状态——第一次遍历总会触发大量 cache miss,后续才趋于稳定。真想测“稳态遍历”,得先预热:在计时外完整遍历 1–2 次,再开始正式测量。


















