流式处理必须绕过io.readall和json.marshal,因其会一次性将大文件全量加载至内存引发oom;应使用io.copy、json.encoder、csv.reader等流式接口配合bufio缓冲分块处理。

流式处理必须绕过 io.ReadAll 和 json.Marshal
直接用 io.ReadAll 或 json.Marshal 读取/序列化大文件,等于把整个文件塞进内存——1GB 文件 ≈ 1GB 内存占用,GC 压力陡增,协程一多就触发 OOM。这不是性能问题,是设计错误。
-
io.ReadAll会分配一块连续内存容纳全部字节,无法中断、不可控 -
json.Marshal不仅分配内存,还会做反射遍历 + 字符串拼接 + 临时 buffer 拷贝,开销远超数据本身 - HTTP handler 中这么干,一次上传就可能拖垮整个服务实例
io.Copy 是流式传输的底层基石,但不能包打天下
io.Copy 确实能边读边写、内存恒定,但它只做“搬运工”,不处理结构、不跳 BOM、不校验格式、不支持分块回调。它适合纯二进制透传(如 ZIP 下载),但不适用于需要解析或转换的场景。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 默认内部缓冲区为 32KB,对机械盘或高延迟网络可显式套
bufio.NewReaderSize(f, 64*1024)提升吞吐 - 若目标
io.Writer是http.ResponseWriter,需提前设好 Header,否则写入时 panic - 它不返回已复制字节数,调试或进度上报需自己包装
io.Reader或用io.CopyN
结构化数据流必须用 json.Encoder / csv.Reader + bufio
JSON 或 CSV 大文件不是“读完再处理”,而是“边读边解、边生成边写”。标准库提供对应流式接口,但必须手动组合缓冲层,否则性能断崖下跌。
-
json.Encoder要求输入是 Go 值,不能直接喂chan;动态流需手写{/[开头、循环enc.Encode(item)、最后补}/] -
csv.Reader默认缓冲仅 4KB,GB 级文件必须用bufio.NewReaderSize(f, 64*1024)包裹,否则引号跨 buffer 就解析失败 - 字段数不固定时,务必设
reader.FieldsPerRecord = -1,否则遇到空行或末尾逗号直接 panic
gRPC 和 HTTP multipart 场景下,流式本质是“分块协议+手动控制”
gRPC 的 BidiStreaming 或 HTTP 的 multipart/form-data,都不是开箱即用的流——它们只是传输通道,真正流式行为由你控制 Send() / Recv() 频率和 buffer 大小决定。
- gRPC 客户端别调
os.ReadFile()再发,要用固定 buffer(如 32KB)循环file.Read(buf)+client.Send() - HTTP 服务端别调
r.ParseMultipartForm(32,应直接用 <code>multipart.NewReader(r.Body, boundary)手动逐 part 解析 - buffer 太小(1MB)易触达 gRPC
maxMessageSize限制(默认 4MB)
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










