连续批处理

概述

连续批处理(Continuous Batching)是一种大语言模型(LLM)推理服务中的关键优化技术,用于提升 GPU 利用率和推理吞吐量。它最早由 vLLM 等项目推广普及,核心思想是动态地、持续地向正在执行的推理批次中添加新请求,而非等待整批请求全部完成后再开始下一批。

传统静态批处理的不足

在传统的静态批处理(Static Batching)模式下:

  1. 推理服务将多个请求打包成一个 batch 送入 GPU。
  2. 必须等 batch 中所有请求都完成推理后,才能处理下一批。
  3. 由于不同请求的输入长度和输出长度差异很大(例如有的请求生成 10 个 token,有的生成 1000 个 token),短请求必须等待长请求,导致 GPU 大量空闲。
静态批处理示意:
Batch 1: [Req A ████████████████████] ← 长请求,拖慢整批
[Req B ████] ← 短请求,必须等待 Req A
[Req C ██████] ← 同样在等待
↓ GPU 空闲等待整批结束
Batch 2: [Req D ████]
[Req E ██████████████]
...

连续批处理的工作原理

连续批处理解决了上述问题,其核心机制:

  • 随时出队:当 batch 中某个请求完成推理(生成 EOS token 或达到最大长度),立即将其移出 batch。

  • 随时入队:一旦有空位,立即将等待队列中的新请求加入当前 batch,GPU 无需等待整批结束。

  • 迭代级调度:在每个 token 生成迭代(iteration)中,batch 的组成都可以动态变化。

连续批处理示意:
Iter 1: [Req A] [Req B] [Req C]
Iter 2: [Req A] [Req B] [Req C]
Iter 3: [Req A] [Req B] ← Req C 完成,移出
Iter 4: [Req A] [Req B] [Req D] ← Req D 立即加入
Iter 5: [Req A] [Req D] ← Req B 完成,移出
Iter 6: [Req A] [Req E] [Req D] ← Req E 立即加入
...

不同批处理对比

处理方式 工作机制 优势 劣势 适用场景
无批处理 一次处理一个请求 实现简单 GPU资源利用率极低,吞吐量差 开发测试
静态批处理 等待请求凑满一个固定大小的批次后统一处理,完成后才处理下一批 相比无批处理,GPU利用率提升 延迟高:必须等待最慢的请求完成;资源浪费;快请求需等待慢请求 离线批量任务
动态批处理 设置一个最大批次大小的时间窗口,在窗口期内累积请求,然后处理 延迟比静态批处理低 对于生成时间不确定的LLM,仍存在等待问题 图像生成等任务时长相近的场景
连续批处理 以token为粒度,随时完成请求随时释放资源,并接入新请求 吞吐量最高,GPU空闲时间极短,延迟表现优秀 调度算法复杂 LLM在线推理的高并发场景

连续批处理的调度过程

详细涉及 Prefill 与 Decode 两个阶段。在 Prefill 阶段,系统将新加入请求的输入序列并行处理,请求进入waiting队列,调度器会检查资源是否够用,若够用,从waiting队列移除进入runining队列,查询计算并缓存 KV Cache,同时生成第一个输出 token。此时 batch 中的请求可以处于混合状态:已有请求正在 Decode,新请求开始 Prefill。在 Decode 阶段,同样维护waiting和running两个队列,batch 中的请求逐个 token 生成,一旦某个请求生成 EOS 或达到最大长度,立即将其移出 batch,释放的 slot 可供新请求立刻进入 Prefill。这种迭代级调度使得 Prefill 与 Decode 可以无缝交替,最大程度压满 GPU 计算资源,同时降低单个请求的等待延迟

连续批处理

连续批处理依赖几个关键的组件:

  1. 精细的调度器
  2. 高效的PageAttention内存管理
  3. Token级别的执行与资源释放

总结

静态批处理是"拼车"——凑满人才发车,有人先到也得等;

连续批处理是"地铁"——每站到站即上下,座位永远不空跑。