小文件(10mb)或需流式处理时,bufio.reader 配合固定缓冲区(如 64kb)通常吞吐更高且内存可控;os.readfile 一次性分配全量内存,易触发 gc 或 oom。

Go 里 os.Readfile 和 bufio.Reader 读大文件谁更快?
直接说结论:小文件(os.ReadFile 更简洁、不差;大文件(>10MB)或需流式处理时,bufio.Reader 配合固定缓冲区(如 64KB)通常吞吐更高,且内存可控。
原因不是“bufio 更高级”,而是 os.ReadFile 内部会一次性 make([]byte, size) —— 文件多大就申请多大内存,容易触发 GC 压力或 OOM;而 bufio.Reader 只维护固定大小的缓冲区,边读边处理,适合管道、解析、过滤等场景。
常见错误现象:os.ReadFile 在读取几百 MB 日志时卡顿、内存飙升;或用 bufio.Scanner 读超长行直接 panic(默认 64KB 行限制)。
- 用
bufio.NewReaderSize(f, 64*1024)显式设缓冲区,别依赖默认值(defaultBufSize = 4096) - 若需按行处理,改用
bufio.Reader.ReadString('\n')或bufio.Reader.ReadBytes('\n'),避开Scanner的行长限制 - 测试时记得关掉系统 page cache 干扰:Linux 下可用
sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"清缓存再测真实磁盘性能
Go 写文件时 os.WriteFile vs os.Create + io.WriteString 性能差异在哪?
os.WriteFile 是原子写入:先写临时文件,再 rename,适合配置、JSON 等小数据,但每次调用都涉及至少两次 syscall(open + write + close),且无法追加。
立即学习“go语言免费学习笔记(深入)”;
而 os.Create + io.WriteString(或 w.Write())是打开后复用句柄,适合日志、批量导出等持续写场景,但你要自己管同步和关闭。
容易踩的坑:用 os.WriteFile 循环写日志——每条日志都新建文件,磁盘 I/O 次数爆炸;或者用 *os.File.Write 但忘了 file.Sync(),断电丢数据。
- 高频小写(如每秒百次)→ 改用
bufio.NewWriter包一层,调w.Flush()控制刷盘节奏 - 必须保证落盘 → 写完调
file.Sync(),但注意它很慢,别每写一次都 Sync - 追加写 → 用
os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644),别用os.WriteFile
Go 测试磁盘 I/O 性能时,为什么 time.Now() 测不准?
因为 Go 调度器和 GC 会干扰 wall-clock 时间;尤其在短时高频读写中,time.Now() 开销本身可能占到微秒级,掩盖真实 I/O 差异。
更可靠的做法是用 runtime.ReadMemStats 观察分配量,配合 os.Stat 检查文件大小变化,再用 go tool trace 抓住阻塞点——比如是不是卡在 syscall.Read 上,还是被调度器挂起。
典型误判:看到 os.ReadFile 耗时 8ms 就认为“慢”,但 trace 发现其中 6ms 是 GC STW,实际磁盘只花了 0.3ms。
- 基准测试统一用
go test -bench=.,它自动绕过 GC 干扰,采样更稳 - 测单次操作用
runtime.nanotime()替代time.Now(),精度到纳秒且无 GC 分配 - 务必在不同负载下测:空闲机器 vs 同时跑 rsync 的机器,结果可能差 5 倍
Linux 下 Go 程序的 O_DIRECT 和 O_SYNC 能随便开吗?
不能。Go 标准库的 os.OpenFile 不支持传 O_DIRECT(需 syscall.RawSyscall 自己调 open);而 O_SYNC 虽支持(os.O_SYNC),但会让每次 Write 都等磁盘确认,吞吐暴跌,日常开发几乎不用。
真实高性能场景(如数据库、存储引擎)才考虑绕过 page cache 直写磁盘,但代价是:缓冲区地址必须页对齐、长度是 512B 倍数、不能用 Go 的 slice(得用 syscall.Mmap 或 cgo 分配),稍错就 panic。
多数人混淆了“同步”和“持久化”:fsync 是持久化,O_SYNC 是每次写都 fsync —— 这是反模式。
- 想降低延迟波动 → 用
file.Sync()定期刷,而不是开O_SYNC - 想绕过 page cache → 先确认业务真需要(比如 mmap 大文件做随机访问),再用 cgo 调
open(..., O_DIRECT) - 容器环境要特别小心:
O_DIRECT在 overlayfs 或 rootless pod 中可能静默退化为普通写
磁盘 I/O 性能测试最麻烦的从来不是代码怎么写,而是你根本不知道当前是在测 SSD、NVMe、机械盘,还是被容器卷、网络存储、甚至 tmpfs 欺骗了 —— 动手前先 cat /sys/block/*/queue/rotational 和 lsblk -d -o name,rota,log-sec,phy-sec 看清底层。











