一、批处理基础:从单样本到批量推理的思维转变
大家好,我是你们这堂课的主讲人。今天咱们聊聊批处理。
说实话,我刚入行做推理优化那会儿,觉得批处理就是个「把多个请求攒一起发」的简单操作。后来被现实狠狠教育了一次——有一次线上服务延迟飙升,查了半天,发现是批处理策略没设计好,反而拖垮了系统。嗯,从那以后,我再也不敢小看这个基础概念了。
1.1 什么是批处理?
批处理,说白了就是「一次处理多个样本」。在推理场景下,我们把多个用户的请求(比如多个对话、多个图片生成任务)打包成一个批次,一次性喂给模型。
你想想看,模型推理时,最耗时的其实是矩阵运算。GPU 这类硬件天生适合并行计算——一次算 1 个矩阵和一次算 8 个矩阵,时间差不了太多。这就是批处理能提速的根本原因。
核心定义:批处理(Batching)是指将多个独立的推理请求合并为一个批次,利用硬件并行能力同时处理,从而提升整体吞吐量。
1.2 单样本推理 vs 批处理推理
我习惯用一张对比表来说明两者的差异。这张表我做了很多次培训都在用,很直观。
| 对比维度 | 单样本推理 | 批处理推理 |
|---|---|---|
| 处理方式 | 一次处理 1 个请求 | 一次处理 N 个请求 |
| 硬件利用率 | 低(GPU 经常空闲等待) | 高(计算单元满载运行) |
| 延迟表现 | 单请求延迟低(无等待) | 单请求延迟略高(需凑批) |
| 吞吐量 | 低(每秒处理请求数少) | 高(每秒处理请求数多) |
| 内存开销 | 低(仅需一个样本的显存) | 高(需容纳整个批次) |
| 适用场景 | 实时交互、低延迟要求 | 离线批量、高吞吐场景 |
这里有个关键点:批处理不是免费的午餐。它用「单请求延迟的轻微增加」换来了「整体吞吐量的大幅提升」。我在项目中遇到过不少团队,一上来就把 batch size 拉到 64,结果显存爆了,服务直接挂掉。这就是没理解「收益与代价」的关系。
1.3 批处理的核心收益
为什么要用批处理?我总结了三个核心收益,也是你在设计系统时必须想清楚的三件事。
收益一:吞吐量提升
吞吐量,就是单位时间内能处理多少个请求。批处理对吞吐量的提升,效果非常显著。
举个例子:假设模型处理 1 个请求需要 10ms,处理 8 个请求需要 20ms。单样本推理时,每秒能处理 100 个请求。而批处理(batch size=8)时,每秒能处理 8 × (1000/20) = 400 个请求。吞吐量直接翻了 4 倍。
我的经验:在实际项目中,batch size 从 1 增加到 8,吞吐量通常能提升 3-5 倍。但再往上加,收益会递减。我曾经试过把 batch size 从 64 加到 128,吞吐量只提升了 15%,显存却翻了一倍。得不偿失。
收益二:资源利用率优化
GPU 的计算单元(CUDA cores、Tensor Cores)非常「怕饿」。单样本推理时,计算单元经常处于半饥饿状态——数据还没准备好,核心在空转。批处理相当于给 GPU 喂了「满汉全席」,让所有计算单元都忙起来。
我习惯用 GPU 利用率这个指标来衡量。单样本推理时,利用率可能只有 20%-30%。合理设置批处理后,利用率能轻松达到 80% 以上。你想想看,同样的硬件,利用率翻了三倍,这不就是白捡的性能吗?
收益三:内存带宽利用优化
这一点容易被忽略。GPU 从显存读取数据是有带宽限制的。单样本推理时,每次读取只拿一个样本的数据,带宽利用率很低。批处理时,一次读取一批数据,带宽被充分压榨。
说白了,批处理让 GPU 的「搬运工」(内存控制器)和「工人」(计算单元)都忙起来了,系统整体效率自然就上去了。
避坑指南:我曾经犯过一个错误——为了追求高吞吐,把 batch size 设得很大,结果显存不够,触发了 OOM(Out of Memory)。更糟糕的是,OOM 后 GPU 驱动会卡死,整个服务需要重启。所以,批处理一定要考虑显存上限。建议先做一次显存压力测试,找到安全的 batch size 上限。
1.4 批处理的核心逻辑:一张图看懂
下面我用一张 SVG 图来展示批处理的核心逻辑。这张图我画了很多版本,这个版本最简洁,适合初学者理解。
这张图想表达的核心思想是:批处理把「多次串行推理」变成了「一次并行推理」。N 个请求不再需要 N 次前向传播,而是合并成一次。这就是吞吐量提升的根源。
1.5 什么时候不该用批处理?
说了这么多批处理的好处,我也得泼点冷水。批处理不是万能的,有些场景下它反而有害。
- 实时交互场景:比如语音助手、在线客服。用户等不了你凑批,延迟必须控制在 100ms 以内。这时候单样本推理更合适。
- 请求长度差异极大:如果一批请求中,有的输入很短(10 个 token),有的很长(4096 个 token),短的请求会被长的拖死。这就是「木桶效应」。
- 显存极度紧张:有些部署环境显存只有 4GB,连一个批次都塞不下。这时候强行批处理只会导致 OOM。
我的建议:在实际系统中,我通常采用「动态批处理」策略——设置一个最大等待时间(比如 50ms),在这段时间内收集请求,凑够一定数量就执行推理。如果等待时间到了还没凑够,也直接执行。这样既保证了延迟可控,又能享受批处理带来的吞吐提升。
1.6 本章小结
批处理的核心就三句话:
- 是什么:把多个请求打包,一次推理。
- 为什么好:提升吞吐量、优化资源利用率、压榨内存带宽。
- 注意什么:显存上限、延迟约束、请求长度差异。
下一章,我们会深入讨论批处理的具体实现策略——包括静态批处理、动态批处理、连续批处理等。但在此之前,我建议你先想清楚一个问题:你的业务场景,到底更看重吞吐量还是延迟?这个问题的答案,决定了你后续所有的设计选择。