4、并发推理场景:在线服务(实时)、离线批处理(吞吐)、边缘设备(延迟与功耗)

聊到并发推理,我脑子里第一个蹦出来的问题就是:你到底要服务谁?

这可不是一句废话。你想想看,一个给用户实时聊天的AI,跟一个半夜跑数据报表的AI,它们对GPU的要求能一样吗?完全不一样。我个人习惯把并发推理场景拆成三大类来思考——在线服务、离线批处理、边缘设备。这三兄弟,脾气秉性完全不同。

4.1 在线服务:低延迟是命根子

在线服务,说白了就是用户点一下,模型就得立刻出结果。比如智能客服、实时翻译、AI绘画的即时生成。这类场景,延迟就是用户体验。我见过太多项目,模型精度再高,如果响应时间超过500ms,用户直接就跑了。

核心矛盾: 单个请求的延迟 vs 整体吞吐量。你不能为了吞吐把单个请求卡死。

我在项目中遇到过最头疼的事:一个在线翻译服务,并发量一上来,GPU显存就爆了。为什么?因为每个请求都独立加载模型,显存被重复占用了。后来怎么解决的?显存池化。

具体做法是这样的:

  • 预分配一块固定大小的显存池,比如4GB。
  • 所有请求进来,都从池子里借显存,用完立刻归还。
  • 池子满了?那就排队等,或者直接拒绝新请求(这叫背压)。

嗯,这里要注意:在线服务的批处理大小(batch size)通常很小,甚至就是1。因为你要等凑够一批再算,延迟就上去了。我个人建议,在线服务用动态batch——设置一个超时时间,比如5ms,到了时间不管凑没凑够,直接开算。

我的小技巧: 在线服务的显存池,最好预留20%的冗余。别问我怎么知道的,线上流量毛刺能让你措手不及。

4.2 离线批处理:吞吐量就是一切

离线批处理,场景完全反过来。比如每天凌晨跑用户画像、批量生成商品描述、大规模数据标注。这类任务,用户不坐在屏幕前等,所以延迟不是问题,吞吐量才是王道。

你想想看,同样的GPU,一次处理1张图和一次处理32张图,吞吐量能差出十几倍。所以离线场景的核心思路就是:把batch size往大了怼,直到显存撑爆为止。

我曾经做过一个离线推理任务,模型是BERT-large,单卡推理太慢了。后来我做了三件事:

  1. 显存池预分配超大块,比如一次分配8GB,专门给大batch用。
  2. 流水线并行:把模型切成几段,不同GPU分别算不同段,数据像流水线一样流过去。
  3. 异步数据加载:CPU提前把下一批数据准备好,GPU算完一批立刻接下一批,中间不卡顿。

结果呢?吞吐量提升了4倍。但代价是显存占用几乎翻倍。这就是典型的用空间换时间。

避坑指南: 我曾经把batch size设得太大,结果显存溢出,整个任务崩了,前面算的几小时全白费。所以离线场景一定要做显存预算检查——算一下当前模型+数据需要多少显存,别盲目贪大。

离线批处理的显存池策略,跟在线服务完全相反:

维度 在线服务 离线批处理
batch size 小(1~8) 大(32~256)
显存池分配 小粒度、快速回收 大块预分配、长期持有
核心指标 P99延迟 吞吐量(样本/秒)
典型框架 Triton Inference Server TensorFlow Serving + 自定义调度

4.3 边缘设备:在夹缝中求生存

边缘设备,比如手机、摄像头、IoT盒子。这类场景最让人头疼——既要低延迟,又要低功耗,显存还小得可怜。你想想看,一个Jetson Nano才4GB显存,还要跑实时检测,怎么搞?

我做过一个边缘端的行人检测项目,设备是Jetson Xavier NX。刚开始直接把服务器上的模型搬过去,结果帧率只有5fps,功耗还飙到15W。后来我做了三件事:

  • 模型量化:从FP32降到INT8,显存占用直接砍掉75%,速度翻倍。
  • 显存池复用:边缘设备没有虚拟内存,显存池必须提前规划好。我预先分配了输入、输出、中间特征图三块固定区域,推理时反复用,绝不动态申请。
  • 功耗感知调度:如果检测到电池电量低,自动降低batch size或者跳帧处理。
核心原则: 边缘设备的显存池,必须是静态预分配的。动态分配在边缘端是灾难——分配慢不说,还可能碎片化导致OOM。

嗯,这里有个坑。边缘设备的显存池大小,不能按峰值来设。为什么?因为峰值场景可能只占1%的时间,但你为了这1%多占了一倍显存,平时就浪费了。我建议的做法是:按90%分位点来分配显存池,剩下的10%场景,用降级策略处理——比如降低分辨率、跳过某些帧。

我的经验: 边缘设备上,显存池碎片化是隐形杀手。我曾经连续跑了72小时,显存池碎片化导致分配失败,设备直接重启。解决方案是:定期整理显存池,或者用伙伴算法(Buddy System)来管理。

4.4 三种场景的显存池设计对比

说了这么多,我画了一张图来总结这三种场景的显存池设计思路。你看完应该就明白了。

并发推理场景显存池设计对比 在线服务(实时) • 延迟敏感:P99 < 100ms • 小batch:1~8 • 显存池:小粒度、快速回收 • 动态batch + 超时机制 • 预留20%冗余 • 典型框架:Triton 核心指标:P99延迟 离线批处理(吞吐) • 吞吐优先:样本/秒 • 大batch:32~256 • 显存池:大块预分配 • 流水线并行 • 异步数据加载 • 需做显存预算检查 核心指标:吞吐量 边缘设备(延迟+功耗) • 延迟+功耗双约束 • 显存小:2~8GB • 显存池:静态预分配 • 模型量化(INT8) • 功耗感知调度 • 防碎片化(伙伴算法) 核心指标:能效比 显存池设计没有银弹,必须根据场景特点做取舍

你看,三种场景对显存池的要求完全不同。在线服务要快,离线批处理要大,边缘设备要省。没有一种显存池策略能通吃所有场景。

最后说一句:显存池不是万能的。它解决的是显存分配和回收的效率问题,但如果你模型本身太大,或者数据量远超预期,该加卡还是得加卡。我曾经在一个项目里死磕显存池优化,折腾了两周,吞吐只提升了15%。后来加了一张卡,直接翻倍。嗯,有时候硬件才是最快的优化。

总结一句话: 理解你的场景,选择正确的显存池策略,比盲目优化代码重要一百倍。

想要更多资料,联系可可