在单 GPU 上并发服务多个 LLM 请求时,CUDA 流(Stream)与内存池的协同设计直接决定吞吐上限。本文从同步原语、内存分配、调度策略三个层面,拆解多流推理的底层实现细节,并给出可落地的工程参数。
流同步原语:延迟同步是核心原则
CUDA 流保证同流内操作顺序执行,但流间可并行。多流 LLM 推理中最常见的性能陷阱是过度同步—— 在每个算子后调用 cudaStreamSynchronize 或 cudaDeviceSynchronize 会强制全局屏障,彻底抵消流级并行的优势。
正确的同步策略遵循延迟同步原则:仅在请求真正需要结果时同步,而非每个内核或拷贝后都同步。具体实现上,采用 cudaEventRecord 标记关键节点,配合 cudaStreamWaitEvent 实现流间依赖,避免全局阻塞。TensorRT 的最佳实践表明,每个工作线程应持有独立的执行上下文与 CUDA 流,同步操作推迟到请求完成或缓冲区重用前执行。
流同步的粒度选择需权衡延迟与资源占用。对于 TTFT(Time To First Token)敏感的场景,可在 Prefill 阶段后插入一次轻量同步;而对于吞吐优先的 Decode 阶段,则应保持完全异步直到生成结束。
内存池设计:预分配替代动态分配
LLM 推理中的内存分配热点集中在三类区域:权重 staging 缓冲区、激活值临时空间、以及 KV Cache。重复的 cudaMalloc/cudaFree 不仅引入分配器竞争,还会导致内存碎片,在并发场景下成为显著瓶颈。
内存池的核心思想是预分配 slabs 或块分配器,将运行时分配转换为池内指针移动。对于 LLM 推理,KV Cache 往往是实际内存瓶颈,池设计应优先保证持久化的 per-request 状态空间,再考虑临时 scratch 空间。
推荐的分层池策略:
- L1 池:固定大小的页块(如 256 tokens / 块),按请求按需分配,支持动态扩缩
- L2 池:大页缓冲区用于权重上传与激活值 staging,生命周期与推理会话绑定
- L3 池:设备内存的细粒度 sub-allocator,处理算子内部的临时分配
池容量参数建议按 GPU 显存的 70-80% 设定预留,剩余空间用于动态缓冲与 CUDA Runtime 开销。
优先级调度与带宽分配
CUDA 流支持优先级设置(cudaStreamCreateWithPriority),范围通常为 -5(最高)到 0(默认)。在多流 LLM 推理中,优先级调度可用于区分实时性要求不同的请求类型:
- 高优先级流(-3 至 -5):用于交互式请求的 Prefill 阶段,确保首 token 快速返回
- 默认优先级流(0):批量 Decode 阶段,追求整体吞吐
- 低优先级流(1 至 3,若支持):后台任务如 KV Cache 压缩或上下文换入换出
优先级调度的有效前提是内核级并行度未饱和。当单个流的 kernel 已占满 SM(Streaming Multiprocessor)或内存带宽时,后续流的优先级设置对实际执行顺序影响有限。此时应优先考虑算子融合与内存访问模式优化,而非单纯增加流数量。
流间同步屏障的工程实现
多流协作场景(如 Pipeline Parallelism 的 micro-batch 调度)需要显式的流间同步机制。推荐采用 ** 事件链(Event Chain)** 模式:
cudaEvent_t evt;
cudaEventCreate(&evt);
// Stream A 完成关键阶段后记录事件
cudaEventRecord(evt, streamA);
// Stream B 等待该事件后再继续
cudaStreamWaitEvent(streamB, evt, 0);
此模式相比全局 cudaDeviceSynchronize 具有更低的同步开销,且允许非依赖流继续执行。对于需要严格顺序的 multi-turn 对话或 speculative decoding 场景,事件链是维持正确性的关键原语。
可落地的优化参数清单
基于上述分析,整理多流 LLM 推理的底层调优参数:
| 参数类别 | 推荐值 | 说明 |
|---|---|---|
| 每 GPU 流数 | 2-4 | 超过 4 个流在 SM 饱和后收益递减 |
| 流优先级 | Prefill: -3, Decode: 0 | 首 token 延迟与吞吐的权衡 |
| 内存池预留 | 显存 70-80% | 剩余用于动态分配与 Runtime |
| KV Cache 块大小 | 256 tokens | 平衡碎片与分配频率 |
| 同步策略 | 每请求结束时同步一次 | 避免算子级同步 |
| Pinned Memory | 启用 | 异步 H2D/D2H 拷贝的前提 |
验证多流优化效果的指标应关注实际重叠度(通过 Nsight Systems 的 GPU 时间线观察),而非单纯的流数量。若 SM 利用率已接近 100%,增加流数不会提升吞吐,反而可能因上下文切换引入额外开销。
结论
Multi-Stream LLM 的性能优化不是简单的 "加流即加速"。核心在于:每个工作线程绑定独立流与执行上下文,以预分配内存池替代动态分配,延迟同步至请求边界,并通过优先级调度区分延迟敏感与吞吐敏感任务。当 GPU 计算或带宽已饱和时,应转向算子融合、KV Cache 压缩等方向寻求突破,而非继续堆叠流数量。
资料来源
- NVIDIA Developer Forums: TensorRT Inference using multi stream
- arXiv: Inf-MLLM: Efficient Streaming Inference of Multimodal Large Language Models on a Single GPU
内容声明:本文无广告投放、无付费植入。
如有事实性问题,欢迎发送勘误至 i@hotdrydog.com。