优先使用 bufio.Reader/Writer 替代原生 os.File 读写以减少系统调用;合理设置缓冲区大小;避免同一文件复用多个 bufio 实例;高频小文件拷贝宜用 sync.Pool 复用缓冲区;大文件读写需权衡内存与性能。
bufio.Reader 和 bufio.Writer 替代原生 os.File 读写直接对 *os.File 调用 Read 或 Write 会频繁触发系统调用,尤其小数据量时性能极差。缓冲区能批量处理底层 I/O,显著降低 syscall 次数。
实操建议:
bufio.NewReader + ReadString / Scan

bufio.NewWriter,记得在关闭前调用 Flush
*os.File 同时套多个 bufio 实例——会造成读写错位或丢数据io.Copy 的隐式内存分配io.Copy 内部使用 32KB 临时缓冲区,看似省心,但在高频小文件拷贝(如微服务间文件中转)中,反复分配/释放会抬高 GC 压力。
实操建议:
[]byte 缓冲池:var bufPool = sync.Pool{
New: func() interface{} { return make([]byte, 0, 32*1024) }
}io.CopyBuffer(dst, src, bufPool.Get().([]byte)) 替代裸 io.Copy
buf := bufPool.Get().([]byte) io.CopyBuffer(dst, src, buf[:0]) bufPool.Put(buf)
dst 是网络连接(net.Conn),某些实现(如 TLS 连接)可能不支持部分写,此时强制大缓冲反而触发多次 Write,需实测验证os.OpenFile 参数要精确控制用 os.ReadFile 读小文件方便,但超过几 MB 就容易爆内存;而盲目加 O_SYNC 或 O_DIRECT 又会拖慢吞吐——关键在匹配实际需求。
实操建议:
os.OpenFile(path, os.O_RDONLY, 0) + bufio,禁用 O_APPEND 等无关 flagO_WRONLY | O_CREATE | O_APPEND + os.Chmod 设置权限,**不要加 O_SYNC**——它会让每次 Write 等磁盘落盘,吞吐暴跌;改用定期 fsync 或日志轮转时 flushO_DIRECT,但要求 buffer 地址和长度均对齐 512 字节,否则 syscall.EINVAL
Golang 协程轻量,但每个 *os.File 占一个 fd,Linux 默认每进程 1024 个;同时多 goroutine 写同一文件还会因内核级锁导致串行化。
实操建议:
semaphore 控制同时打开的文件数,例如 sem := make(chan struct{}, 10) // 最多 10 个并发文件操作sync.Mutex 包裹 Write 调用(仅当写入频率低时)lsof -p $(pidof yourapp) | wc -l,超 800 就该排查是否漏关 Close
defer f.Close() 不保险——若函数提前 return,defer 可能没执行;更稳妥的是在 error 分支显式关,并用 if f != nil { f.Close() } 防空指针真正卡住性能的往往不是单次 read/write 多慢,而是缓冲区大小、fd 复用方式、以及是否在不该同步的地方强求同步。这些点不压测就很难暴露。