在GPU算力平台进行推理部署时,逐请求执行往往无法充分利用GPU;直接等待固定大批次,又会让低流量请求延迟过高。动态批处理通过"最大批量+短等待窗口"收集请求,在吞吐和响应时间之间取得平衡。本文用PyTorch和异步队列搭建最小实现,并给出压测与回退方法。
一、问题背景
GPU擅长并行计算,多个形状一致的样本合批后通常能提升设备利用率。但线上请求到达时间不均匀,输入长度也可能不同。如果无条件合批,会出现队头阻塞、填充浪费和超时。大模型训练中的Batch概念不能直接照搬到在线服务,动态批处理必须围绕服务等级目标设计。
无论使用GPU服务器租用还是AI算力平台,都要先测单请求基线,再决定合批上限。批量越大不一定越好,显存峰值与长尾延迟同样重要。
二、环境准备
准备可运行的PyTorch模型、固定测试集和异步Web框架。记录模型版本、输入形状、GPU显存及单请求耗时。润云智算提供GPU资源与镜像环境,可从官网了解当前服务信息;本文不假定具体显卡配置,参数应按实测调整。
三、实操步骤
1. 建立单请求基线
python
model.eval().cuda()
with torch.inference_mode():
for _ in range(20):
model(sample.cuda())
torch.cuda.synchronize()
记录P50、P95延迟、每秒请求数、GPU利用率和峰值显存。预处理、排队和后处理要分别计时,避免只优化模型前向。
2. 定义请求队列
python
import asyncio
from dataclasses import dataclass
@dataclass
class Job:
tensor: object
future: asyncio.Future
queue = asyncio.Queue(maxsize=256)
设置队列上限可防止突发流量无限占用内存。队列满时应返回明确的限流或重试信号,而不是继续堆积。
3. 按批量和时间窗口收集
python
async def collect_batch(max_batch=8, wait_ms=5):
jobs = [await queue.get()]
deadline = asyncio.get_running_loop().time() + wait_ms / 1000
while len(jobs) < max_batch:
timeout = deadline - asyncio.get_running_loop().time()
if timeout <= 0:
break
try:
jobs.append(await asyncio.wait_for(queue.get(), timeout))
except asyncio.TimeoutError:
break
return jobs
等待窗口从较小值开始测试。低流量时及时发出小批次,高流量时尽快填满批次。
4. 执行合批并拆分结果
python
async def worker():
while True:
jobs = await collect_batch()
batch = torch.stack([j.tensor for j in jobs]).cuda()
try:
with torch.inference_mode():
outputs = model(batch)
for job, output in zip(jobs, outputs):
job.future.set_result(output.cpu())
except Exception as exc:
for job in jobs:
if not job.future.done():
job.future.set_exception(exc)
生产代码还需处理请求取消、输入校验和优雅退出,不能让单个异常导致整组Future悬挂。
5. 处理不同长度输入
文本或音频请求可按长度区间进入不同队列,再在同一区间内填充。记录有效Token与填充Token比例,若填充过多,表面批量增大但实际吞吐可能下降。超长请求可走独立队列,避免阻塞短请求。
6. 压测并确定回退策略
分别测试低、中、高并发,扫描max_batch与wait_ms组合,观察P95/P99、吞吐、显存和队列长度。更换GPU算力平台后应重新压测。若队列等待超过阈值,可立即发送当前批次;若显存不足,则降低批量并保留逐请求模式。润云智算环境同样应以真实请求完成验收。
四、常见问题与解决方案
1、吞吐提升但延迟变差?
等待窗口或批量上限过大,应按业务延迟目标缩小,并观察排队时间。
2、动态批处理频繁OOM?
输入长度和显存峰值不稳定,应按长度分桶、降低上限并预留安全空间。
3、多Worker会更快吗?
多进程可能复制模型并争抢GPU。先用单模型Worker验证,再逐步扩展。
4、请求取消后结果如何处理?
写回前检查Future状态,并清理对应资源,避免无效后处理。
五、总结
动态批处理的核心不是追求最大Batch,而是用可控等待换取并行效率。可靠实现需要有限队列、超时收集、异常分发、长度分桶和端到端压测。对深度学习服务而言,只有吞吐提升且长尾延迟仍达标,才适合投入推理部署;大模型训练所用批量经验只能作为参考。