一、批处理基础:从单样本到批量推理的思维转变

大家好,我是你们这堂课的主讲人。今天咱们聊聊批处理。

说实话,我刚入行做推理优化那会儿,觉得批处理就是个「把多个请求攒一起发」的简单操作。后来被现实狠狠教育了一次——有一次线上服务延迟飙升,查了半天,发现是批处理策略没设计好,反而拖垮了系统。嗯,从那以后,我再也不敢小看这个基础概念了。

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 图来展示批处理的核心逻辑。这张图我画了很多版本,这个版本最简洁,适合初学者理解。

批处理核心逻辑示意图 请求 1 请求 2 请求 3 请求 N 批处理 Batch Size = N 大模型 并行推理 一次前向传播 批量输出结果 多个请求 → 合并为批次 → 一次模型推理 → 批量输出

这张图想表达的核心思想是:批处理把「多次串行推理」变成了「一次并行推理」。N 个请求不再需要 N 次前向传播,而是合并成一次。这就是吞吐量提升的根源。

1.5 什么时候不该用批处理?

说了这么多批处理的好处,我也得泼点冷水。批处理不是万能的,有些场景下它反而有害。

  • 实时交互场景:比如语音助手、在线客服。用户等不了你凑批,延迟必须控制在 100ms 以内。这时候单样本推理更合适。
  • 请求长度差异极大:如果一批请求中,有的输入很短(10 个 token),有的很长(4096 个 token),短的请求会被长的拖死。这就是「木桶效应」。
  • 显存极度紧张:有些部署环境显存只有 4GB,连一个批次都塞不下。这时候强行批处理只会导致 OOM。

我的建议:在实际系统中,我通常采用「动态批处理」策略——设置一个最大等待时间(比如 50ms),在这段时间内收集请求,凑够一定数量就执行推理。如果等待时间到了还没凑够,也直接执行。这样既保证了延迟可控,又能享受批处理带来的吞吐提升。

1.6 本章小结

批处理的核心就三句话:

  • 是什么:把多个请求打包,一次推理。
  • 为什么好:提升吞吐量、优化资源利用率、压榨内存带宽。
  • 注意什么:显存上限、延迟约束、请求长度差异。

下一章,我们会深入讨论批处理的具体实现策略——包括静态批处理、动态批处理、连续批处理等。但在此之前,我建议你先想清楚一个问题:你的业务场景,到底更看重吞吐量还是延迟?这个问题的答案,决定了你后续所有的设计选择。


专注资料整理