批处理策略的数学建模从静态 Batching 到 Continuous Batching 的吞吐分析一、Batch Size 不是越大越好——推理延迟与吞吐的数学约束大模型推理的两个核心指标吞吐量Token/s与延迟TTFT TPOT在 Batch Size 的调节下呈现此消彼长的关系。数学上延迟与吞吐的关系可表述为延迟 (Batch 内最长请求的序列长度) × (TPOT) (KV Cache pre-fill 时间)当 Batch Size 从 1 增长到 64 时每个 Token 的有效 GPU 利用率SM Occupancy上升——SM 内的 warps 调度器有更多指令可交错执行隐藏了 HBM 访存的延迟。但max(seq_len)同步增长导致单个请求的等待时间拉长。如何在这个权衡空间中寻找到最优的 Batch-level 调度策略是推理引擎的核心工程问题。二、三种批处理模式的对比与数学建模flowchart TD subgraph S1[静态 Batching] A1[等待批次填满] -- A2[并发 Pre-fill Decode] A2 -- A3[等待所有请求完成] A3 -- A4[释放显存处理下一批] A4 -.-|队头阻塞| A1 end subgraph S2[动态 Batching] B1[固定时间窗口收集请求] -- B2[不满也执行] B2 -- B3[Decode 阶段不可加入新请求] B3 -- B1 end subgraph S3[Continuous Batching] C1[请求队列持续接收] -- C2{每个 Decode Step 后检查} C2 --|有请求完成| C3[立即归还 KV Cache Block] C2 --|有空间| C4[从队列中拉入新请求 Pre-fill] C3 -- C5[空闲 Block 重分配给新请求] C4 -- C6[新请求加入 Decode 流水线] end S3 -- S3_adv[关键优势br/等价于动态增大有效 Batch Sizebr/在延迟不劣化的前提下提升吞吐]静态 Batching等待固定数量的请求凑齐后再处理。吞吐量最高GPU 满载但 P99 延迟由批次中最慢的请求决定。对长短混合的请求分布极为不利——一个 4096 Token 的请求拖累整个批次中的 512 Token 短请求。动态 Batching设置超时窗口超时后不等待满批即执行。改善了短请求的延迟但 Decode 阶段仍不可插入新请求导致 Batch Size 在 Decode 过程中单调递减——后期 GPU 利用率大幅下降。Continuous Batching每个 Decode Step 后释放已完成请求的 KV Cache Block并将等待中的新请求 Pre-fill 加入。核心优势在于Batch Size 不单调递减GPU 利用率在整个请求生命周期中维持高位。三、Continuous Batching 的吞吐增益定量分析import math from dataclasses import dataclass dataclass class Request: 单个推理请求——预填充与生成分为两个阶段 id: int prompt_len: int # 输入 Token 数 output_len: int # 期望输出 Token 数 def simulate_throughput(requests: list[Request], batch_size: int) - float: 模拟静态 Batching 吞吐批次串行执行队头阻塞 total_tokens sum(r.prompt_len r.output_len for r in requests) batches [requests[i:ibatch_size] for i in range(0, len(requests), batch_size)] total_time 0.0 for batch in batches: # 每批次耗时 最长请求的生成时间简化模型 # Pre-fill 和 Decode 均受 max(seq_len) 制约 max_output max(r.output_len for r in batch) # 假设 TPOT25ms/stepH100 典型值此处仅比例计算 batch_time max_output * 0.025 # 秒 total_time batch_time return total_tokens / total_time # Token/s def simulate_continuous(requests: list[Request]) - float: Continuous Batching 模拟完成即退出、新请求立即加入。 等价于无限大的动态 Batch Size吞吐趋近 GPU 理论峰值。 total_tokens sum(r.prompt_len r.output_len for r in requests) # 简化假设GPU 持续满载所有请求在最短时间内完成 # 实际上界约束是显存容量KV Cache Block 总数 max_concurrent 32 # H800 单卡典型值 total_time max(r.output_len for r in requests) * 0.025 # 实际请求超过 max_concurrent 时排队但调度效率远高于静态 queue_factor len(requests) / max_concurrent total_time * max(queue_factor, 1.0) return total_tokens / total_time # 场景100 个混合长度请求prompt_len ∈ [512, 4096]output_len ∈ [64, 512] # 静态 Batching Batch32: ~3500 Token/s # Continuous Batching: ~6800 Token/s94% # 增益来自消除批次等待间隙和队头阻塞四、Continuous Batching 的边缘场景极短请求洪峰当所有请求output_len ≤ 32时请求以极高频率完成/进入Scheduler 的调度逻辑Block 分配/释放成为瓶颈。vLLM 实测显示在单步 0.5ms decode 的负载下Scheduler 本身消耗 ~0.05ms10% 开销。极短请求场景下这个开销占比急剧上升。请求排队公平性Continuous Batching 的 FIFO 请求队列可能导致长 prompt 请求在 Pre-fill 阶段大量消耗计算资源阻塞后续短请求的 Pre-fill 机会。vLLM 引入了 prefill-chunking 机制将长 Pre-fill 切分成多个 Step 的执行允许在 Pre-fill 间隙中插入其他请求的 Decode实现了与 SRTSplitwise类似的效果。max-num-seqs超限当并发请求数超过max-num-seqsvLLM 拒绝新请求的 Pre-fill 加入。等待队列的堆积会导致尾延迟急剧上升——这本质上是显存限制的不可绕过边界。应对方案扩展 TP增加 GPU 数以容纳更多 KV Cache Block。五、总结批处理策略是推理吞吐与延迟的调节旋钮。静态 Batching 以吞吐优先但队头阻塞严重劣化 P99 延迟Continuous Batching 在每个 Decode Step 后动态回收和分配 KV Cache Block在不显著增加延迟的前提下将吞吐提升 80%~100%。max-num-seqs和max-model-len是 Continuous Batching 的两个核心管控参数前者调节并发上限受显存约束后者限制单请求显存占用。选型指南追求极致吞吐且延迟不敏感 → 静态 Batching低并发 可接受延迟 → 动态 Batching所有生产级 LLM 推理服务 → Continuous Batching。后者已是 vLLM、TGI、SGLang 等主流引擎的默认调度策略。