Go文件I/O基准测试必须用func BenchmarkXxx(b *testing.B)函数并加-bench参数运行;需明确测延迟还是吞吐,合理选用os.O_SYNC/O_DSYNC、缓冲区大小及f.Sync()时机,并清理系统缓存确保结果可靠。
用 testing.B 做文件 I/O 基准测试,不是跑 go test -v 就完事了
Go 的基准测试必须用 testing.B 类型的函数,命名以 Benchmark 开头,且需显式启用基准模式。直接运行 go test 不会执行它们;得加 -bench 参数,比如 go test -bench=.。漏掉这个参数,函数压根不跑,你还以为代码没生效。
常见错误现象:写好了 BenchmarkWriteSmallFile,执行 go test 输出全是 ok,但没任何耗时数据——八成是忘了加 -bench。
- 基准函数签名必须是
func BenchmarkXxx(b *testing.B) - 循环体必须套在
b.ResetTimer()和b.ReportAllocs()之间(若关心内存) - 别在
b.N循环外创建待测文件或缓存,否则测的是初始化开销 - 每次迭代应真实触发 I/O:
os.WriteFile、io.Copy、bufio.Writer.Flush都要显式调用
os.O_SYNC 和 os.O_DSYNC 会让 Write 变慢十倍以上
默认 os.OpenFile(..., os.O_WRONLY|os.O_CREATE, 0644) 是异步写入,系统缓存接管后就返回,不代表数据已落盘。想测“真实持久化性能”,必须加 os.O_SYNC(同步元数据 + 数据)或 os.O_DSYNC(仅同步数据)。但代价巨大:在普通 SATA 盘上,小块写可能从 0.1ms 跳到 10ms+。
-
os.O_SYNC确保 write 返回前,数据和 inode 时间戳都刷进磁盘 -
os.O_DSYNC只保证数据落盘,不等时间戳,略快一点 - SSD 上差距缩小,但依然存在;NVMe 上可能只差 2–3 倍
- 测试前用
sync命令清空系统页缓存(Linux),否则首次运行快、后续变慢,结果不可复现
缓冲区大小对 bufio.Reader/Writer 性能影响极大
默认 bufio.NewReaderSize(f, 4096) 在读大文件时明显拖慢吞吐。实测中,把 buffer 从 4KB 改成 64KB,顺序读取 1GB 文件的吞吐可提升 30%–50%,尤其在机械盘上。但 buffer 不是越大越好:超过 1MB 后收益趋平,还可能因内存分配抖动拉高 p99 延迟。