最可靠方法是用 std::chrono::steady_clock 多次循环测量并防止编译器优化:赋值给 volatile auto 或加内存栅栏,避免单次测量、clock() 或 time()。

用 std::chrono 测单次函数耗时最可靠
直接用 std::chrono::high_resolution_clock,别碰 clock() 或 time() —— 前者精度低、后者单位模糊,测 C++ 函数容易差一个数量级。Windows 下 QueryPerformanceCounter 虽快但跨平台麻烦,std::chrono 是标准解。
常见错误是只测一次就下结论:函数可能被优化掉、受 CPU 频率波动或缓存预热影响。真实场景下必须循环多次取平均,且要确保编译器没把待测函数整个优化掉(加 volatile 或用返回值防止死代码消除)。
- 用
std::chrono::steady_clock更稳妥,它不随系统时间调整跳变 - 起始和结束时间都用
.time_since_epoch().count()转整数,避免浮点误差累积 - 若函数执行太快(纳秒级),
high_resolution_clock在某些旧编译器上可能退化为毫秒精度,可先用std::chrono::duration_cast<:chrono::nanoseconds>(end - start).count()</:chrono::nanoseconds>检查最小分辨率
怎么防止编译器优化干扰测量结果
Clang/GCC/MSVC 默认开启 O2/O3 时,空函数、纯计算函数常被整个删掉,或者内联后边界模糊。测出来是 0ns,不是真快,是没测到。
关键动作就两个:强制保留函数调用 + 强制使用返回值。别用 asm volatile("") 这种黑魔法,太依赖编译器行为。
立即学习“C++免费学习笔记(深入)”;
- 把待测函数返回值赋给
volatile auto result = func();,编译器不敢删 - 如果函数无返回值,加一句
asm volatile("" ::: "rax");(x86-64)或更通用的std::atomic_thread_fence(std::memory_order_seq_cst);打乱优化顺序 - 测试前加
std::chrono::sleep_for(std::chrono::microseconds(1));避免 CPU 空转导致频率降频,影响单次测量稳定性
多线程环境下测函数时间要注意什么
同一核心上多个线程争抢时,std::chrono::high_resolution_clock 读取本身开销会浮动,而且上下文切换会让时间片不连续。单纯套个 std::thread + join() 测出来的不是函数真实耗时,是“从创建线程到结束”的总延迟。
- 真正要测并发函数性能,得在 worker 线程内部打点,主控线程只负责启动和收集结果
- 避免用
std::this_thread::sleep_for做同步,它不精确;改用std::condition_variable+std::mutex控制时机 - 注意
std::chrono::steady_clock在不同线程里是独立可比的,但system_clock可能因 NTP 调整产生负差值,绝对不用
为什么 std::chrono::duration_cast 容易出错
类型转换不匹配会导致截断或溢出。比如把微秒级差值 cast 成 std::chrono::milliseconds 再 .count(),结果永远是 0;反过来,用 nanoseconds 接毫秒级差值,高位全零但占内存大,不影响精度但浪费。
- 优先用
auto diff = end - start;让类型自动推导,再按需 cast:比如std::chrono::duration_cast<:chrono::microseconds>(diff).count()</:chrono::microseconds> - 别写
diff.count() / 1000手动换算——整除丢精度,且单位语义丢失 - 输出调试时用
std::chrono::duration<double std::milli></double>直接转成带小数的毫秒浮点数,比整数更直观
实际写的时候,最常漏的是「防止优化」和「多次采样」这两步。跑一次就信结果,基本等于没测。


















