连续批处理:原理介绍、与经典批处理的区别、在LLM推理中的应用

各位同学,今天我们来聊聊连续批处理。说实话,这个技术是我在优化LLM推理服务时,觉得最「解渴」的一个方案。你想想看,经典批处理虽然好,但有个硬伤——它得等所有请求都到齐了才开始处理。这就像等公交车,非得等满一车人才发车,那前面等的人得多着急?

一、经典批处理的痛点

先说说经典批处理。它的逻辑很简单:攒一批请求,一起算。比如你有一个推理服务,来了10个请求,系统会等这10个请求都到齐了,然后一次性喂给模型。

这样做的好处是GPU利用率高,毕竟一次性处理多个请求,矩阵运算的效率上去了。但问题也很明显——延迟高。尤其是当请求到达时间不均匀时,先到的请求得一直等着,直到攒够一批。

我在项目中遇到过这样一个场景:一个在线翻译服务,用户发来一段文本,结果等了3秒才返回。为什么?因为系统在等后面几个请求凑成一批。用户早就关页面了。嗯,这就是经典批处理的典型问题——牺牲延迟换吞吐

经典批处理的三个硬伤:

  • 请求必须等齐才能开始处理
  • 批大小固定,无法动态调整
  • 长请求会阻塞短请求(队头阻塞)

二、连续批处理:原理介绍

连续批处理,说白了就是「不等了」。它允许请求随时加入、随时离开。你想想看,这就像高速公路的ETC通道,每辆车到了就直接过,不用等前面凑够一队。

具体原理是这样的:

  1. 请求到达即处理:只要有请求进来,系统就把它加入当前正在执行的批次中。
  2. 请求完成即退出:某个请求的推理完成了,它就直接从批次中移除,不用等整个批次结束。
  3. 动态调整批大小:系统根据当前负载和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执行 请求完成 → 退出 继续生成下一token 循环 新请求加入 核心思想:请求随时加入,完成即退出,动态调整批次

从这张图能看出来,连续批处理的核心就是一个动态循环。请求到达后,调度器决定是否加入当前批次。GPU执行完一轮后,完成的请求退出,未完成的继续下一轮。同时,新请求可以随时加入。

六、实现要点

如果你打算自己实现连续批处理,有几点需要注意:

  • 内存管理:KV Cache需要动态分配和回收。建议用内存池,避免频繁分配释放。
  • 调度策略:可以按请求长度、优先级、等待时间等因素来调度。我个人习惯用「最短剩余时间优先」策略。
  • 批大小控制:不是越大越好。批大小受GPU显存限制,需要动态调整。
  • 延迟与吞吐的平衡:连续批处理虽然降低了延迟,但如果批大小太小,GPU利用率会下降。需要找到一个平衡点。

注意:连续批处理不是万能的。如果你的请求量很小(比如每秒只有几个请求),经典批处理可能更简单有效。连续批处理的优势在高并发、请求长度差异大的场景下才明显。

好了,关于连续批处理就讲到这里。这个技术在实际项目中非常实用,尤其是做LLM推理服务优化的同学,建议好好研究一下。


专注资料整理