测多线程总耗时应使用 std::chrono::steady_clock 获取墙上时间,起点在 main() 前静态初始化,终点需显式等待所有线程结束(如 join 或 wait),避免用 clock() 或 system_clock。

测多线程总耗时,别用 clock()
多线程下 clock() 返回的是所有线程 CPU 时间之和,不是你感知的“过了多久”。比如 6 线程并行跑满 5 秒,clock() 可能返回接近 30 秒——它告诉你 CPU 干了 30 秒活,但用户只等了 5 秒。
真正要测“程序从启动到结束花了多少真实时间”,必须用墙上时钟(wall-clock time),且得是单调不跳变的。
-
std::chrono::steady_clock是首选:跨平台、纳秒级精度、不受系统调时影响 - Linux 下可选
clock_gettime(CLOCK_MONOTONIC, &ts),语义等价但需手动处理timespec - 绝对不要用
std::chrono::system_clock测间隔——NTP 同步或手动改时会导致差值突变甚至为负 - Qt 项目直接用
QElapsedTimer,start()/elapsed() 一行搞定,底层也是CLOCK_MONOTONIC
怎么记录主线程启动和所有工作线程结束的时间点
关键不是“测某段代码”,而是“测整个程序生命周期”。起点必须在 main() 开头就捕获,终点必须等所有线程真正退出后才读取。
- 起点写成全局静态变量:
static const auto program_start = std::chrono::steady_clock::now();,确保在main()执行前完成初始化 - 终点不能只靠
main()结束——如果还有后台线程没join()或detach(),程序可能提前退出,测不准 - 必须显式等待所有线程完成:
worker_thread.join();或用std::jthread(C++20)自动 join - 若用
std::async,记得保存std::future并调用.wait(),否则析构时可能不阻塞
高频测时场景下,duration_cast 的坑
每次调用 std::chrono::duration_cast 都有少量开销,对每毫秒都要测的循环(如游戏帧逻辑),反复 cast 会引入噪声。
- 需要毫秒整数:先 cast 成
std::chrono::milliseconds,再调.count(),别每次重算 - 需要带小数的秒(如日志输出):用
std::chrono::duration<double>(d).count()</double>,比duration_cast<:chrono::nanoseconds>(d).count() / 1e9</:chrono::nanoseconds>更安全(避免整数溢出) - 别直接打印
auto d = end - start;——输出的是纳秒级整数,不是秒,极易误读 - Linux 下
clock_gettime返回的timespec要自己算tv_sec * 1e9 + tv_nsec,单位统一后再除 1e9 得秒
跨平台时,CLOCK_PROCESS_CPUTIME_ID 和 getrusage 的取舍
如果你真想测“这个进程总共占用了多少 CPU 时间”(含所有线程),而不是墙上时间,就得换 API。
-
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)是 POSIX 标准做法,精度高、开销低,但 macOS 不支持 - macOS 上得用
getrusage(RUSAGE_SELF, &ru),取ru.ru_utime + ru.ru_stime,精度通常只有微秒级 - Windows 对应的是
GetProcessTimes(),需把FILETIME转成 100ns 单位再换算 - 注意:
CLOCK_PROCESS_CPUTIME_ID统计的是进程级 CPU 时间,fork 后子进程独立计时;而clock()在多线程下累加所有线程,语义混乱
测多线程程序运行时间,本质是选对时钟源 + 控制好测量边界。最常被忽略的是:起点必须早于任何线程创建,终点必须晚于所有线程终止——中间哪怕漏掉一个 join(),测出来的就不是真实耗时。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











