std::chrono::steady_clock 是唯一适合测量耗时的时钟,因其单调递增、不受系统时间调整影响;应直接用 steady_clock::now() 记录起止时间并计算差值,避免转为 time_t 或字符串导致精度丢失。

为什么 std::chrono::steady_clock 是唯一靠谱的选择
用 std::chrono::system_clock 估算剩余时间会出错,因为系统时间可能被 NTP 调整、手动修改或夏令时切换干扰,导致 duration 突然跳变。而 std::chrono::steady_clock 单调递增、不随系统时间调整,是唯一适合测量耗时的时钟。
- 必须用
steady_clock::now()记录起始和当前时间点 - 不要转成
time_t或字符串再算差值——精度直接丢光 - Windows 上
steady_clock底层通常映射到QueryPerformanceCounter,Linux 下多为CLOCK_MONOTONIC,都满足毫秒级稳定采样
auto start = std::chrono::steady_clock::now(); // ... 工作循环中 auto now = std::chrono::steady_clock::now(); auto elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
进度条里怎么算「还剩多久」才不跳变
剩余时间(ETA)不是简单用 elapsed_ms / progress * (1.0 - progress),那样在进度卡顿、抖动或初始几帧时极易爆炸(比如 progress == 0 或刚从 0.001 跳到 0.002)。
- 用滑动窗口维护最近 N 次「进度增量 → 耗时」的样本,例如每增加 0.5% 进度记一次耗时
- 只对有效样本(耗时 > 0、进度差 > 0)做加权平均,丢弃离群值(如单次耗时 > 均值 3 倍)
- 初始阶段(样本数 < 3)直接返回
-1或空字符串,不显示 ETA,避免误导
别用总耗时 / 总进度这种全局比值——IO 阻塞、GC、调度延迟会让早期估算严重偏高。
printf 和 std::cout 刷新太慢,怎么做到毫秒级实时刷新
终端刷新本身有开销,频繁写入会拖慢主线程,且多数终端对 \r 回车的响应不是真正“毫秒级”——实际刷新率受终端缓冲、字体渲染、甚至 SSH 延迟影响。
立即学习“C++免费学习笔记(深入)”;
- 每 50–100ms 刷新一次就够了,人眼根本看不出区别,但 CPU 开销降一个数量级
- 用
std::cout << "\r" << buffer << std::flush,\r回车必须在最前,不能用\b退格模拟 - Windows 控制台默认行缓冲,需调用
setvbuf(stdout, nullptr, _IONBF, 0)关闭 C stdio 缓冲(C++ 流不受此影响,但混用时要注意) - 如果输出到文件或管道,
\r无效,得改用\n+ 清屏逻辑,或者直接关掉进度条
跨平台毫秒精度下,Windows 的 GetTickCount64 能不能替代 steady_clock
能读,但不该用。GetTickCount64 在 Windows 7+ 上确实返回毫秒级单调值,但它有两大硬伤:
- 分辨率不保证:旧硬件或电源管理下可能只有 10–16ms 间隔,
QueryPerformanceCounter才是真高精度 - C++ 标准库的
steady_clock在 Windows 就是封装了QueryPerformanceCounter,你手动调用反而绕过标准抽象,失去可移植性
同理,Linux 下别手写 clock_gettime(CLOCK_MONOTONIC, &ts) —— steady_clock 就是为你干这个的,而且 duration_cast 自动处理单位换算,少出 bug。
真正的难点不在“怎么显示”,而在“什么时候敢信这个 ETA”。样本不够、进度非线性、底层阻塞不可见——这些都会让毫秒数字变得比不显示更误导。宁可少刷新、晚显示、加个「估算中…」,也别在前 3% 进度就报出「剩余 2.3s」。


















