Continuous Batching
连续批处理会在每个解码步骤重新构建 LLM 服务器的批次,让已完成的请求退出、新请求加入,从而让 GPU 持续满负荷运行。
连续批处理也称为迭代级调度或在途批处理,是一种用于生成模型服务的调度技术:服务器在每个解码步骤都会重建批次。一个序列完成后会立即离开批次并返回结果,等待中的请求则在下一步加入。首尔大学和 FriendliAI 的 Gyeong-In Yu 等人在 OSDI 2022 上的 Orca 中提出了这种方法,并报告称,在相同延迟下,处理 GPT-3 175B 的吞吐量比 NVIDIA FasterTransformer 高 36.9 倍。2023 年,随着 vLLM 和 Hugging Face Text Generation Inference 采用这一方法,“连续批处理”这一名称开始普及;如今,它已成为服务引擎的默认调度器,这些引擎支撑着大型语言模型(LLMs)。
请求级批处理为何浪费 GPU#
文本生成每次前向传播都会生成一个token,而不同请求所需的前向传播次数差异很大:是或否的回答只需几个 token,而代码文件可能长达数千个 token。在静态批处理中,一组请求会一直保持在一起,直到其中最长的请求完成。较早结束的序列会让对应槽位闲置,新到的请求则要等整组请求处理完毕才能开始,这会增加排在长请求后面的每个短请求的推理延迟。
NVIDIA Triton 等服务器采用的动态批处理是请求级方案:它会收集在短时间窗口内到达的请求,将它们作为一个批次运行直至完成。这适用于每个输入的计算成本固定的模型,例如图像分类器或目标检测器,因为每个输入都能在一次前向传播中完成。Ultralytics YOLO 预测模式会根据输入源,将多个请求级的 YOLO26 输入组成批次:包含摄像头 URL 的 .streams 文件会作为一个批次运行,每个流取最新的一帧,因此 8 个流会以批次大小 8 运行;batch 参数则会将视频、目录或 .txt 图像列表中的帧组成一个批次,一次前向传播完成处理。
迭代级调度的工作原理#
调度器会为每个活动序列运行一个解码步骤,然后检查它是否遇到序列结束 token 或达到长度上限。完成的序列会返回并释放其内存;如果KV 缓存空间足够,队列中的请求就会加入。Orca 会在解码其他序列的同一步骤中处理(预填充)新请求的提示词;当前的引擎也会通过分块预填充来实现这一点。
要混合不同长度的序列,还需要另一个概念,Orca 将其称为选择性批处理。对每个 token 独立处理的操作,例如每个 Transformer 层中的大型矩阵乘法,会同时处理所有序列中的所有 token。注意力则按序列运行,因为每个序列的上下文长度各不相同。
此模拟展示了在一块每次解码四个序列的 GPU 上调度相同的八个请求:
import heapq
output_lengths = [5, 50, 8, 12, 40, 3, 30, 7] # tokens each queued request will generate
slots = 4 # sequences the GPU decodes together at each step
# Static batching: each group of 4 runs until its longest request finishes
static_steps = sum(max(output_lengths[i : i + slots]) for i in range(0, len(output_lengths), slots))
# Continuous batching: the next request takes the first slot that frees up
slot_free_at = [0] * slots
for length in output_lengths:
start = heapq.heappop(slot_free_at)
heapq.heappush(slot_free_at, start + length)
continuous_steps = max(slot_free_at)
for name, steps in [("static", static_steps), ("continuous", continuous_steps)]:
print(f"{name}: {steps} decode steps, slots busy {sum(output_lengths) / (steps * slots):.0%}")静态批处理需要 90 个解码步骤,槽位有 43% 的时间处于忙碌状态。连续批处理在 50 步内完成,也就是最长请求所需的步数,槽位有 78% 的时间处于忙碌状态。
局限与配套技术#
更大的运行中批次会提高总吞吐量,但每个步骤耗时也更长,因此每个输出 token 的耗时会增加。因此,引擎会限制并发序列数和每步处理的 token 数量;vLLM 将这两项限制分别公开为 max_num_seqs 和 max_num_batched_tokens,并会将连续批处理与一些相关技术结合使用:
- PagedAttention:将 KV 缓存分配到小块中,使已完成的序列能够立即释放内存,而新序列只占用实际需要的空间。
- 分块预填充:将长提示词拆分成多个片段,避免新请求的预填充阻塞其他请求的解码。
- 推测解码:在批次较小时效果最佳,因为大型连续批次已经占用了 GPU 的大部分计算资源。










