应使用 std::chrono::high_resolution_clock 测文件 i/o 耗时,因其在 linux/macos/msvc 上提供微秒级真实挂钟精度;避免 clock()(返回 cpu 时间,i/o 期间几乎不变)和 steady_clock(可能计入调度抖动,测时偏长)。

用 std::chrono 测文件读写耗时,别用 clock()
直接结论:用 std::chrono::high_resolution_clock,不是 std::chrono::steady_clock 或 std::clock()。前者在多数平台(Linux/macOS/MSVC)提供微秒级真实挂钟精度,后者要么不随系统时间调整(steady_clock 适合测间隔但可能略“钝”),要么是 CPU 时间(clock()),对 I/O 这种阻塞操作完全失真。
常见错误现象:clock() 返回值几乎不变,或 steady_clock 测出的时间比实际长得多(尤其在 SSD + 异步 I/O 场景下,调度抖动被计入)。
- Windows 上
high_resolution_clock通常映射到 QueryPerformanceCounter,精度 ≈100ns - Linux 上它一般等价于
CLOCK_MONOTONIC_RAW(若可用),避开 NTP 调整干扰 - 别依赖
duration_cast<microseconds></microseconds>的“四舍五入”——用count()取原始 tick 数再除以频率更稳
ifstream / ofstream 同步模式影响极大,必须关掉
默认 C++ iostream 是同步 C stdio 的(std::ios_base::sync_with_stdio(true)),这会让每次 read() 或 write() 都触发 libc 缓冲层+系统调用,测出来的是“带锁+缓冲策略”的总耗时,不是你真正想优化的磁盘 I/O 或内存拷贝部分。
使用场景:你想对比 mmap vs read()、或测试不同缓冲区大小对吞吐的影响——这时必须剥离 iostream 自身开销。
- 开头加
std::ios_base::sync_with_stdio(false),并确保没混用printf/scanf - 用
file.rdbuf()->in_avail()判断是否已缓存,避免误把缓冲区读当磁盘读 - 对大文件,显式调用
file.clear()和file.seekg(0)重置状态,否则eofbit会污染后续测量
open() + read()/write() 系统调用更干净,但要注意 O_DIRECT 和对齐
如果目标是逼近底层 I/O 性能,绕过 C 库和 iostream 更可靠。但直接用 open() 会暴露很多隐藏约束——尤其 O_DIRECT 模式,它跳过 page cache,但要求:
- 缓冲区地址必须是 512B(或文件系统逻辑块大小)对齐,用
posix_memalign()分配,不能用new或malloc - 读写偏移和长度都需对齐,否则
read()返回-1并设errno = EINVAL - 普通
O_SYNC会强制刷盘,耗时暴涨 10–100 倍,除非你真在测 fsync 性能,否则别开
示例片段(测纯读):
int fd = open("data.bin", O_RDONLY | O_DIRECT);<br>void* buf;<br>posix_memalign(&buf, 512, 4096);<br>auto t1 = std::chrono::high_resolution_clock::now();<br>ssize_t n = read(fd, buf, 4096);<br>auto t2 = std::chrono::high_resolution_clock::now();
多次运行取最小值,不是平均值
文件 I/O 耗时方差极大:page cache 命中/未命中、磁盘寻道、CPU 频率波动、其他进程抢占……平均值会被异常高延迟拖垮,失去参考价值。
性能影响:一次冷读(cache miss)可能比热读慢 100 倍;SSD 在垃圾回收时某次 write 延迟突增到 10ms 很常见。
- 至少跑 5–10 次,取
std::chrono::duration_cast<nanoseconds>(t2 - t1).count()</nanoseconds>的最小值 - 每次运行前用
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)清 cache(Linux),或sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"(需 root) - 用
taskset -c 0 ./bench绑核,减少调度抖动
最易忽略的点:没清 buffer cache 就反复跑,第二次开始全是内存读,结果看着飞快,但上线后全卡在磁盘上。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











