动态批处理需兼顾吞吐与延迟,核心是用 asyncio.queue 双阈值攒批、padding 对齐输入并同步生成 attention_mask,避免梯度关闭误替代批处理逻辑。

为什么不能直接用 torch.no_grad() 做动态批处理
因为 torch.no_grad() 只是关闭梯度计算,它不解决请求到达时间不一致、输入长度不同、需要等待多个请求凑够 batch size 才能推理的问题。真实服务场景中,用户请求是流式到达的,硬等固定数量会引入不可控延迟,而立刻处理单请求又浪费 GPU 利用率。
核心矛盾在于:GPU 推理吞吐和端到端延迟之间的权衡。动态批处理的本质是「在请求队列里攒一批相似 shape 的输入,在超时或数量阈值触发时统一 forward」。
- 常见错误现象:
RuntimeError: stack expects each tensor to be equal size—— 直接把变长输入(如不同长度的文本 token IDs)堆进torch.stack() - 必须先做 padding 或 truncation,且 padding 长度要对齐到当前 batch 中最长序列,否则无法构造统一
input_ids张量 - 注意
attention_mask必须同步生成,否则模型会误读 padding 位置为有效 token
如何用 asyncio.Queue 实现低开销请求缓冲
别用线程池或全局 list 管理待处理请求——竞争条件难调试,且 Python GIL 限制下线程并不能真正并发处理 I/O。用 asyncio.Queue 配合后台 task 更轻量、可控。
关键不是“怎么存”,而是“什么时候取”。推荐双阈值策略:数量上限(如 8)+ 时间上限(如 100ms),任一满足即触发 batch 构造。
- 每个请求封装为 dict,含
input_ids(list)、callback(coroutine)、timestamp(用于超时判断) - 后台持续运行的
batch_collectortask 轮询 queue,收集后立即调用pad_sequence(..., batch_first=True)对齐 - 避免在 collector 中做模型 forward——forward 必须在专用推理线程或
loop.run_in_executor中执行,防止阻塞 event loop
torch.nn.utils.rnn.pad_sequence 和手动 padding 的区别
pad_sequence 是 PyTorch 官方推荐方式,但它默认按 sequence-first 组织,而 Transformer 类模型普遍要求 batch-first。漏掉 batch_first=True 会导致维度错乱,forward 报 size mismatch。
手动 padding(如用 torch.full 初始化再 slice 赋值)看似灵活,但容易在 mask 构建时出错:比如忘记把 padding 位置设为 0,导致 attention 计算异常。
- 正确用法:
pad_sequence([t1, t2, t3], batch_first=True, padding_value=0) - 对应生成
attention_mask:用(padded_tensor != 0).long(),而非torch.ones_like - 如果模型用了
torch.compile,频繁变长 padding 会导致 graph recompilation,实测 batch 内最大长度变化 >15% 就可能降速
GPU 显存碎片与 batch size 动态调整的实际影响
显存不是线性可分资源。连续小 batch(如每次 2 个 request)可能因 kernel 启动开销和 memory allocator 碎片,反而比一次处理 4 个慢 30%+。但盲目拉高 batch size 又会抬升 P99 延迟。
真正有效的做法是:在 warmup 阶段用典型输入跑几轮,记录不同 batch size 下的 torch.cuda.memory_allocated() 和 end-to-end 耗时,拟合出拐点——通常在显存占用达 70%~80% 时吞吐最优。
- 不要依赖
torch.cuda.max_memory_allocated()做实时限流,它是峰值统计,滞后严重 - 动态调整 batch size 时,优先缩容(减少数量)而非扩容;扩容需预热新 shape 的 CUDA kernel,首次耗时激增
- 若使用 TensorRT 或 TorchScript 导出模型,batch size 必须在编译时固定,此时动态聚合只能在 pre-process 层做,forward 层仍是 static batch
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











