连续批处理:原理介绍、与经典批处理的区别、在LLM推理中的应用
各位同学,今天我们来聊聊连续批处理。说实话,这个技术是我在优化LLM推理服务时,觉得最「解渴」的一个方案。你想想看,经典批处理虽然好,但有个硬伤——它得等所有请求都到齐了才开始处理。这就像等公交车,非得等满一车人才发车,那前面等的人得多着急?
一、经典批处理的痛点
先说说经典批处理。它的逻辑很简单:攒一批请求,一起算。比如你有一个推理服务,来了10个请求,系统会等这10个请求都到齐了,然后一次性喂给模型。
这样做的好处是GPU利用率高,毕竟一次性处理多个请求,矩阵运算的效率上去了。但问题也很明显——延迟高。尤其是当请求到达时间不均匀时,先到的请求得一直等着,直到攒够一批。
我在项目中遇到过这样一个场景:一个在线翻译服务,用户发来一段文本,结果等了3秒才返回。为什么?因为系统在等后面几个请求凑成一批。用户早就关页面了。嗯,这就是经典批处理的典型问题——牺牲延迟换吞吐。
经典批处理的三个硬伤:
- 请求必须等齐才能开始处理
- 批大小固定,无法动态调整
- 长请求会阻塞短请求(队头阻塞)
二、连续批处理:原理介绍
连续批处理,说白了就是「不等了」。它允许请求随时加入、随时离开。你想想看,这就像高速公路的ETC通道,每辆车到了就直接过,不用等前面凑够一队。
具体原理是这样的:
- 请求到达即处理:只要有请求进来,系统就把它加入当前正在执行的批次中。
- 请求完成即退出:某个请求的推理完成了,它就直接从批次中移除,不用等整个批次结束。
- 动态调整批大小:系统根据当前负载和GPU内存,实时调整批次大小。
为什么会这样?因为LLM推理有个特点——每个请求的生成长度不一样。有的请求生成10个token就结束了,有的要生成100个。如果按经典批处理,所有请求都得等最长的那个生成完,这太浪费了。
我记得有一次优化一个对话机器人,用户问「你好」和用户问「请详细介绍一下量子计算的原理」,这两个请求的处理时间差了10倍。用经典批处理,那个「你好」得等量子计算那个请求跑完才能返回。用户肯定觉得这机器人反应太慢了。
三、与经典批处理的区别
咱们用一张表来对比一下:
| 对比维度 | 经典批处理 | 连续批处理 |
|---|---|---|
| 请求到达 | 必须等齐一批 | 随时加入 |
| 请求完成 | 等整批完成 | 随时退出 |
| 批大小 | 固定 | 动态调整 |
| 延迟 | 高(尤其短请求) | 低(短请求优先完成) |
| GPU利用率 | 较高(但有空闲等待) | 更高(持续利用) |
| 实现复杂度 | 简单 | 较复杂 |
从这张表能看出来,连续批处理在延迟和利用率上都有优势。但代价是实现更复杂——你需要管理请求的加入和退出,还要处理GPU内存的动态分配。
四、在LLM推理中的应用
连续批处理在LLM推理中特别有用。为什么呢?因为LLM推理有个核心机制——自回归生成。每次只生成一个token,然后把这个token拼回去,再生成下一个。这个过程是串行的,而且每个请求的生成步数不一样。
用连续批处理,我们可以这样优化:
- 请求级别调度:每个请求独立管理自己的生成进度。生成快的请求先退出,生成慢的继续。
- KV Cache共享:连续批处理可以更高效地利用KV Cache。新加入的请求只需要计算自己的KV Cache,不用重新计算整个批次。
- 优先级调度:可以给短请求更高的优先级,让它们先完成。这在在线服务中特别重要。
我曾经在一个大模型API服务中实践过连续批处理。当时的情况是:用户请求的文本长度差异很大,有的只有几个字,有的是一整篇文章。用经典批处理,短请求的P99延迟高达5秒。改用连续批处理后,P99延迟降到了800毫秒。效果非常明显。
避坑指南:我曾经在实现连续批处理时踩过一个坑——内存碎片。因为请求频繁加入和退出,GPU内存会出现碎片化。后来我用了内存池预分配的策略,才解决了这个问题。建议你在实现时也注意这一点。
五、核心逻辑流程图
下面我用一张SVG图来展示连续批处理的核心逻辑:
从这张图能看出来,连续批处理的核心就是一个动态循环。请求到达后,调度器决定是否加入当前批次。GPU执行完一轮后,完成的请求退出,未完成的继续下一轮。同时,新请求可以随时加入。
六、实现要点
如果你打算自己实现连续批处理,有几点需要注意:
- 内存管理:KV Cache需要动态分配和回收。建议用内存池,避免频繁分配释放。
- 调度策略:可以按请求长度、优先级、等待时间等因素来调度。我个人习惯用「最短剩余时间优先」策略。
- 批大小控制:不是越大越好。批大小受GPU显存限制,需要动态调整。
- 延迟与吞吐的平衡:连续批处理虽然降低了延迟,但如果批大小太小,GPU利用率会下降。需要找到一个平衡点。
注意:连续批处理不是万能的。如果你的请求量很小(比如每秒只有几个请求),经典批处理可能更简单有效。连续批处理的优势在高并发、请求长度差异大的场景下才明显。
好了,关于连续批处理就讲到这里。这个技术在实际项目中非常实用,尤其是做LLM推理服务优化的同学,建议好好研究一下。