std::chrono计时必须同线程同上下文、避免中断与优化干扰;单次I/O需在每次read前后精确打点;用steady_clock;Release编译;注意单位换算与缓冲区大小影响。

std::chrono 计时起点和终点必须在同一线程、同一上下文
跨系统调用(比如 fread 或 std::ifstream::read)前后直接套 std::chrono::high_resolution_clock::now() 是可行的,但前提是不能被信号中断、线程迁移或编译器乱序优化干扰。常见错误是把计时点放在循环外却误以为测的是单次读取——实际测的是整个循环开销。
- 务必把
start = std::chrono::high_resolution_clock::now()放在 每次 read 调用前,end放在其后 - 避免用
std::chrono::steady_clock以外的时钟:它不保证单调,某些系统下system_clock可能因 NTP 调整跳变 - Release 模式下编译,Debug 模式中迭代器检查、边界断言会严重污染耗时数据
计算 MB/s 时注意单位换算和整数截断陷阱
速率不是简单用 bytes_read / duration.count() —— duration.count() 返回的是纳秒(默认)、微秒或时钟周期数,取决于 duration 类型;而 1 MiB = 1024×1024 字节,1 MB = 1000×1000 字节,混用会导致结果偏差 5% 以上。
- 推荐统一用
std::chrono::duration<double std::milli></double>转成毫秒,再除以 1000 得秒 - 速率公式应为:
(static_cast<double>(bytes_read) / (1024.0 * 1024.0)) / (std::chrono::duration_cast<:chrono::duration>>(end - start).count())</:chrono::duration></double> - 别用
auto推导duration类型:end - start默认是nanoseconds,直接除会得到极小浮点数,易被误认为“速度慢”
缓冲区大小显著影响实测吞吐量
读取速率不是文件固有属性,而是 I/O 调度、页缓存、磁盘预读与缓冲区大小共同作用的结果。用 1 字节 buffer 测出来是几百 KB/s,用 1MB buffer 才可能接近磁盘理论带宽。
- 典型合理 buffer 大小:64KB 到 1MB;小于 4KB 容易触发大量系统调用,放大计时误差
- Linux 下可配合
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)清空页缓存再测真实磁盘速率(需 root 权限) - Windows 上注意
FILE_FLAG_NO_BUFFERING要求 buffer 对齐到扇区边界(通常 512B 或 4KB),否则ReadFile直接失败并报ERROR_INVALID_PARAMETER
std::ifstream 在默认构造下不启用二进制模式,会影响大文件读取精度
Windows 下若用 std::ifstream 以文本模式打开二进制文件,遇到 \r\n 会被转成单个 \n,导致 gcount() 返回字节数 ≠ 实际读取的磁盘字节数,速率计算失真。
立即学习“C++免费学习笔记(深入)”;
- 务必加
std::ios::binary标志:std::ifstream f("data.bin", std::ios::binary) - 禁用同步以减少流缓冲干扰:
std::ios_base::sync_with_stdio(false)(对std::cin/std::cout有效,但对独立ifstream无影响) - 如果用 C 风格
fopen+fread,确保用"rb"模式,且检查返回值是否等于请求长度,否则说明 EOF 或 I/O 错误
真正难的不是怎么写那几行 chrono 代码,而是搞清你到底想测什么:是纯内存拷贝速度?页缓存命中率?还是裸盘随机读延迟?不同目标,buffer 策略、预热方式、计时粒度全都不一样。



















