bufio 通过缓冲减少系统调用以提升小数据频繁读写性能,适用于逐行/小段读取、高频小字符串写入及底层开销大的 I/O;不适用于大文件一次性读写;需合理设缓冲大小、避免多次包装和频繁 Flush。

Go 的 bufio 包本身不是用来“提升性能”的魔法工具,而是通过缓冲机制减少系统调用次数,从而在频繁小数据读写时显著降低开销。盲目加 bufio 反而可能拖慢大块数据操作。关键在于理解它的适用场景和正确配置缓冲区大小。
什么时候该用 bufio.Reader / bufio.Writer
适合以下情况:
- 从文件、网络连接或管道中逐行(
ReadString('\n'))、按字节(ReadByte)、或小段(Read)读取数据 - 向文件或网络连接高频写入小字符串(比如日志逐条输出、协议头字段拼接)
- 底层
io.Reader/io.Writer实现开销大(如net.Conn每次 read/write 都涉及系统调用)
不适合:
- 一次性读整个大文件(直接用
os.ReadFile或io.ReadFull更快) - 写入单个超大字节切片(绕过缓冲直接写更高效)
合理设置缓冲区大小是性能关键
默认缓冲区是 4KB(bufio.DefaultBufSize),但并非万能。太小会导致频繁填充/清空;太大浪费内存且可能延迟数据落盘或发送。
立即学习“go语言免费学习笔记(深入)”;
- 读场景:若知道平均行长度或常见读取单位(如 HTTP 请求头约 1–2KB),可设为 2–4 倍该值
- 写场景:匹配目标 I/O 设备的典型块大小(如磁盘常用 4KB,TCP MSS 约 1460 字节),或写入频率 × 单次平均字节数
- 示例:
bufio.NewReaderSize(file, 64*1024)适合批量解析大日志文件;bufio.NewWriterSize(conn, 8192)适合高吞吐 TCP 服务端响应
避免常见低效用法
这些写法会抵消缓冲优势:
-
每次写都
Flush():相当于退化成无缓冲,应攒一批再刷,或仅在必须同步时调用 -
对同一底层 writer 多次包装:如
bufio.NewWriter(bufio.NewWriter(os.Stdout)),只会增加内存和跳转开销 -
读取后不检查
err == io.EOF:导致循环多一次无效读,影响逻辑和性能感知 -
用
ReadString解析不定长二进制协议:它会一直扫描直到找到分隔符,最坏 O(n);改用Read+ 手动解析更可控
配合其他优化效果更佳
bufio 是基础层,需结合上下文设计:
- 读文件时,优先
os.OpenFile+bufio.NewReader,而非os.Open+bufio.NewReader(前者可设 flag 如O_DIRECT,但注意平台支持) - 写日志时,用
bufio.Writer+ 定期 goroutineFlush(),避免阻塞主流程 - 网络服务中,把
bufio.Reader和bufio.Writer与连接生命周期绑定,复用而非反复创建 - 必要时用
bufio.Scanner替代Reader:它内置了合理的缓冲和行切割逻辑,API 更简洁,性能也不输(默认缓冲 64KB)
基本上就这些。bufio 不复杂但容易忽略细节——用对地方、设对大小、避开陷阱,它就能安静高效地干活。











