是,std::chrono::high_resolution_clock测单次I/O耗时不准,因其分辨率不足且受调度、缓存、缓冲等干扰;应重复多次取平均,并用CLOCK_MONOTONIC或裸系统调用测真实延迟。

用 std::chrono::high_resolution_clock 测量单次 I/O 耗时不准?
直接用 std::chrono::high_resolution_clock::now() 包裹一次 read() 或 std::cin,测出来的值经常是 0 或抖动极大——这不是你的代码写错了,而是单次系统调用耗时远低于时钟分辨率(尤其在 SSD 或缓存命中时),且受内核调度、页缓存、预读等干扰严重。
实操建议:
- 必须重复多次(比如 1000–10000 次)同一 I/O 操作,再取平均值,否则数值无意义
- 每次测量前用
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)或drop_caches清空页缓存(仅限 Linux 测试真实磁盘性能) - 避免用
std::cin/std::cout,它们带缓冲和格式化开销;改用read()/write()或fread()/fwrite()更贴近底层 - 注意:Windows 下
high_resolution_clock可能退化为毫秒级,优先用QueryPerformanceCounter
Linux 下绕过 C++ 标准库,用 clock_gettime(CLOCK_MONOTONIC) 更稳
std::chrono 在某些旧编译器或 libc 实现中会间接调用 gettimeofday(微秒但有回跳风险),而 CLOCK_MONOTONIC 是内核提供的单调递增时钟,精度通常达纳秒,且不受系统时间调整影响,更适合 I/O 延迟测量。
示例片段(测一次 read()):
立即学习“C++免费学习笔记(深入)”;
#include <time.h> #include <unistd.h> <p>struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); ssize_t n = read(fd, buf, sizeof(buf)); clock_gettime(CLOCK_MONOTONIC, &end);</p><p>long long us = (end.tv_sec - start.tv_sec) * 1000000LL + (end.tv_nsec - start.tv_nsec) / 1000;
注意:tv_nsec 相减可能为负(秒进位未同步),需做归一化处理;实际建议封装成函数并检查返回值 n 是否为 -1。
为什么 std::fstream 的 read() 测出来比裸 read() 慢很多?
因为 std::fstream 默认启用缓冲(std::filebuf),一次 read() 可能触发多次系统调用或内部 memcpy;它还做 locale、宽字符、异常检查等额外工作。你测的不是“磁盘 I/O”,而是“C++ IOStream 栈的开销”。
若真要对比标准库行为:
- 用
file.rdbuf()->pubsetbuf(nullptr, 0)关闭缓冲(但某些实现不支持) - 用
file.readsome()替代read()避免等待 EOF 检查 - 更可靠的做法:直接用
open()+read(),把文件描述符传给fdopen()再套FILE*,这样可控制缓冲策略(如setvbuf(fp, nullptr, _IONBF, 0))
微秒级测量下,容易被忽略的干扰项
即使时钟本身够准,I/O 耗时也会被以下因素掩盖:
- CPU 频率动态缩放(
scaling_governor设为performance可减少波动) - 进程被抢占:用
sched_setscheduler(0, SCHED_FIFO, ¶m)提升实时优先级(需 root) - TLB/Cache miss:对大文件测试,先
mmap()并memset()触发缺页,再测读取 - 编译器优化:禁用
-O2对 I/O 变量的优化(加volatile或用asm volatile("" ::: "memory")内存屏障)
真正稳定的微秒级 I/O 测量,从来不是调一个函数就完事——它是一连串环境压制、路径隔离和统计降噪的组合操作。


















