Static vs. Dynamic vs. Continuous Batching in LLM Inference
TL;DR · AI 摘要
静态批处理在LLM推理中存在显著延迟问题,动态批处理通过超时窗口优化,连续批处理则需在token层级调度以提升吞吐。
核心要点
- 静态批处理导致请求延迟与批次填充速度强相关,最长请求决定整体处理时间。
- 动态批处理引入超时窗口机制,平衡延迟与吞吐效率。
- 连续批处理通过token级调度,更适合处理长尾请求场景。
结构提纲
按章节快速跳转。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- LLM推理批处理策略
- 静态批处理
- 固定批次大小
- 高延迟风险
- 动态批处理
- 超时窗口机制
- 吞吐-延迟平衡
- 连续批处理
- token级调度
- 长尾请求优化
金句 / Highlights
值得收藏与分享的关键句。
静态批处理中,7个请求需等待第8个到达才会处理,导致显著延迟。
动态批处理通过超时窗口,在等待与吞吐间取得平衡,减少GPU空转。
连续批处理需要在token层级而非请求层级进行调度,更适合LLM特性。
LLM推理中的静态、动态与连续批处理
By
Bala Priya C
on
2026年8月4日
in
人工智能
0
分享
发布
在本文中,你将了解静态批处理、动态批处理和连续批处理在LLM推理中的工作原理,以及为什么这些差异在生产规模下至关重要。
我们将涵盖的主题包括:
- 静态批处理,以及为什么在真实流量下等待完整批处理虽然简单但成本高昂
- 动态批处理,以及如何通过超时窗口解决上述成本问题
- 连续批处理,以及为什么大语言模型需要在令牌级别而非请求级别进行调度
引言
大多数用于服务AI模型的GPU大部分时间都处于空闲状态。一个请求到达后,模型执行它,而GPU则空等下一个请求的到来,尽管以相近的成本可以同时处理多个请求。这种情况在大型语言模型中尤为严重,因为一个请求可能仅需几个令牌就能完成,而另一个请求可能需要处理一千个令牌,因此处理流量的系统必须应对高度不均衡的工作负载,而非连续到达的相同任务。
批处理是解决这个问题的方法。不再针对每个请求单独运行模型,而是将多个请求分组,通过相同的加载权重一次性处理,将原本空闲的GPU周期转化为你已经支付的吞吐量。真正关键的是如何形成这些分组,因为专为均匀工作负载设计的批处理方案一旦请求长度不再可预测就会迅速失效。
静态批处理的工作原理
静态批处理是这个概念最字面的实现:等待固定数量的请求到达后,将它们作为一批同时送入模型处理。在批处理未满之前,任何请求都不会开始处理。如果你设置了8的批大小,第七个到达的请求必须等待第八个到来后,这八个请求才会被处理。
其机制非常直接。请求在队列中累积,当数量达到配置的批大小时,服务器会对所有请求执行一次前向传递,将一组权重共享给整个请求组。这就是其优势所在:从GPU内存加载模型权重成本很高,将这一操作从k次单独执行减少到仅一次,能带来显著的效率提升。这也是为什么静态批处理在需要容忍延迟的批量任务(如对大型存储数据集执行推理)中表现良好,因为这类任务不需要等待单个响应,且整体任务需要快速完成。
但正是这种设计使静态批处理在批量处理时高效,却使其难以应对实时流量:
- 第一个到达的请求必须等待其他所有批处理槽位被填满,因此延迟取决于整个批处理到达的速度,而非该请求单独执行的速度。
- 一旦批处理开始,组内所有请求都必须等待最慢的那个完成,因此五个短请求如果与一个长请求同一批处理,都需要等待那个长请求完成。
- 没有任何方式能限制请求在批处理开始前的等待时间,这使静态批处理几乎无法满足任何有延迟要求的场景。
这个最后的限制正是动态批处理要解决的问题。
动态批处理的工作原理
动态批处理保留了静态批处理的核心思想——通过将请求分组以共享权重负载——但去除了必须等待组别完整才能开始的限制。服务器不再无限期等待批处理填满,而是设置了两个限制:最大批处理大小和超时窗口。无论哪个限制先达到,都会触发批处理的执行。
在实际操作中,这意味着服务器在新批处理的第一个请求到达时立即启动计时器。如果在计时器过期前有足够多的请求填满批处理,它会立即执行,与静态批处理的方式相同。如果计时器先到期,服务器会执行已累积的部分请求,即使这意味着执行一个不完整的批处理。
在Triton推理基准测试中,经过调优的动态批处理配置显著提高了吞吐量,同时仅带来了尾部延迟的适度增加。这是动态批处理中常见的权衡:更高的硬件利用率和请求吞吐量是以略微增加的响应时间作为代价的。
因此,动态批处理为您带来了更高的吞吐量,而超时窗口决定了您为此需要付出多少延迟。
- 设置较短的超时时间可以保护延迟,但代价是运行更小、效率更低的批处理。
- 设置较长的超时时间可以提高填满批处理的可能性,但会增加早期请求在队列中等待的时间。
- 最大批处理大小仍然限制了可以共享一个权重负载的工作量,无论超时设置如何。
这限制了批处理开始前的最坏情况等待时间。但它对第二个问题没有帮助。一旦批处理开始执行,其中的每个请求仍然必须等待,直到该批处理中最慢的请求完成。对于像图像生成器这样的模型,每个输出需要的步骤大致相同,这很少成为问题。但对于大型语言模型,一个请求可能需要5个token而另一个请求可能需要500个token,这意味着短请求经常需要在长请求后面等待,且没有其他解决办法。
连续批处理的工作原理
连续批处理将请求作为调度的基本单位,取而代之的是单个解码步骤。服务器不再等待当前批处理中的所有序列完成才开始下一个批处理,而是独立跟踪批处理中的每个序列,一次处理一个token。
在服务过程中,这是如何运作的。在每个解码迭代中,服务器运行一次前向传递,同时为所有活跃序列生成下一个token。当某个序列发出序列结束token时,它会立即从批处理中移除,而队列中的新请求会在下一个迭代中立即插入到释放的槽位中。
在连续批处理中,没有需要完成的固定批处理。相反,存在一个不断变化的活跃序列滚动集合,其组成几乎在每一步都会发生变化,因此运行连续批处理的GPU很少会等待任何事情。
- 早期完成的序列会立即释放其槽位,而不会阻塞整个批处理直到所有请求完成。
- 新请求只需等待一个迭代即可被考虑分配到空闲槽位,而无需等待整个批处理周期完成。
- 长提示仍然会产生成本,因为新请求的初始预填充传递计算量大,可能在该迭代中延迟所有其他活跃序列的解码步骤,这就是为什么分块预填充将长提示拆分为更小的部分,在多个步骤中处理,而不是一次性全部处理。
许多用于LLM服务的推理框架(包括vLLM、以"in-flight batching"命名的TensorRT-LLM以及TGI)默认采用连续批处理(continuous batching),而非其他模型类型使用的请求级动态批处理(request-level dynamic batching)。在高并发工作负载下,连续批处理通常能实现显著高于请求级动态批处理的吞吐量。相比之下,请求级动态批处理在轻量级工作负载(请求流量低且处理资源竞争较少时)可提供更快的首个token生成时间。
总结
我们讨论的批处理技术本质上解决相同问题,但粒度逐渐细化。静态批处理将一组请求共享权重负载,但组内每个请求都需要等待最慢请求和批处理填充完成。动态批处理通过添加超时限制来控制批处理启动前的等待时间,但一旦批处理开始运行就无法提前返回。连续批处理完全消除了固定大小的批处理单位,以单个解码步骤为粒度进行调度,这正是其成为大规模服务大语言模型标准方案的原因。以下是对比回顾:
| 策略 | 调度单位 | GPU空闲时间 | 延迟表现 | 最佳适用场景 | |------------------|------------------|-------------------|----------------------------------|----------------------------------| | 静态批处理 | 整个批次 | 批次间较高 | 受批次中最慢请求限制 | 无延迟要求的离线任务 | | 动态批处理 | 带超时的完整批次 | 中等 | 受最大批次大小或超时窗口限制 | 固定长度输出(如图像生成) | | 连续批处理 | 单个解码步骤 | 低 | 每请求可变但整体吞吐量高 | 生产环境的自回归LLM服务 |
以下是一些有用的延伸资料:
- 静态、动态和连续批处理 | LLM推理手册
- 动态批处理与并发模型执行 | NVIDIA Triton推理服务器
- 连续批处理与动态批处理在AI推理中的对比 | Baseten
- 连续批处理如何使LLM推理吞吐量提升23倍同时降低p50延迟 | Anyscale
如需了解不同LLM推理框架及其功能优化的对比文章,欢迎在评论区告知!
更多相关内容
- 同时服务多个用户:连续批处理的实现方式
- Python中的静态分析器
- 分类任务的动态集成选择(DES)
- Python中的动态分类器选择集成
- 连续函数的简明介绍
- 机器学习中的连续概率分布
/.entry /think