想象你开了一家小面馆,招牌上写着“AI面馆”。开业初期客人稀疏,你采用最省心的做法:必须凑满8位客人,才点亮灶台一起煮面。这就是“整批接待”。很快你发现两个糟心事:客人A三分钟前就点好菜,却要干等7位新客人来凑数;好不容易凑齐一桌开火,客人B吃得慢,其他七位吃完了也得陪着,空出的座位不许新客人坐。灶台利用率低下,门口排起长队——这就像大模型推理中的静态批处理(Static Batching)。 后来你请来一位“AI厨师长”,它带来一套新玩法——连续批处理(Continuous Batching):只要有客人点完菜就立刻下锅;新客人来了,只要锅里还有位置,随时“加塞”进同一口锅;吃完的客人马上腾出座位,门口那位立刻补上。灶台从不熄火,客人随到随吃。这便是连续批处理:大模型推理时不再死板地整批进、整批出,而是动态地管理每一个请求,让GPU像永不熄火的灶台一样满负荷运转。它是vLLM、TensorRT-LLM等主流推理引擎提升吞吐量的核心秘密。
学完这一篇,你将透彻理解连续批处理的工作原理、核心算法与工程落地要点。结合vLLM等推理框架,你能把GPU吞吐量提升数倍,这是大模型部署工程师必备的核心技能。
可视化演示
展示Continuous Batching在大模型推理中的加速机制:静态批处理的padding浪费、连续批处理的迭代级动态注入与移除、吞吐量提升对比,通过模式切换直观理解请求调度优化原理。
本节配有交互动效(进入视口后自动加载,约 3KB)。
静态批处理:等待最慢请求 固定批次:所有请求同时进入,必须等最长请求完成 Padding浪费:短请求完成后GPU空闲等待 吞吐 = batch_size / max(seq_len_i) 静态批处理GPU利用率低,短请求被长请求阻塞
基本概念
小面馆的包桌制有一个正式名字:静态批处理。它的调度单位是“一整桌”——必须集齐预定人数才开火,整桌同进同出,谁也别想提前走。而流水席模式则对应连续批处理:调度单位从“整桌”细化为“每一位客人、每一道菜”。在大模型的世界里,这个“菜”就是一次解码步(decode step):模型每生成一个token,就像厨师端出一道菜。连续批处理在每个解码步动态决定“此刻谁该在灶台上”,让每个请求按自己的节奏前进,而不是被整桌人绑在一起。
这种以单个请求甚至单次生成为单位的思维方式,就是“请求粒度”(request-level granularity)调度。它带来的最直接收益是吞吐量提升。吞吐量(Throughput)衡量系统单位时间内能完成的请求数,是推理服务的核心业绩指标——就像面馆一天能接待多少桌客人。
从“整桌绑死”到“随到随做”,连续批处理把GPU这块大灶台从“等客凑桌”的尴尬中解放出来。理解了请求粒度这一层,你就握住了整篇文章的钥匙——后面的算法与优化,全部围绕着“如何让每一位客人都吃得快、走得及时”展开。
- N_completed — 完成的请求数在一个统计窗口内成功输出完整回答的请求总数量,像一天里端着碗离开店门的客人人数
- Δt — 时间窗统计所跨越的时间跨度,可以是1秒、1分钟或1小时,像面馆打烊时结算的营业时段
- 比值 — 平均吞吐率完成数除以时间得到单位时间处理速率,直接反映灶台的忙碌程度
问题背景
包桌制的最大痛点发生在“有人吃完却走不了”的时刻。假设一桌八人:七位客人五分钟就吃完了,第八位却慢悠悠吃了半小时。前七位只能干坐——这在推理世界里叫长尾效应(Long-tail Effect):批内不同请求的生成长度不同,短的早该结束,却被迫陪着最长的那条序列一起跑,GPU的有效计算被白白拖住。就像灶台明明空着,也不肯给新客人下锅。
第二个痛点是资源闲置。静态批处理在攒批阶段什么都不干:GPU算力完全空转,显存却已被先到的请求占着。你想象一下:后厨灶台烧着火却不下菜,只因为“还差两位客人”。这种等待在请求稀疏时尤其致命,直接拉低整个系统的资源利用率,而租用GPU的账单却一分不少——这就是算力成本居高不下的根源。
第三,排队延迟。请求到达时间随机,静态批处理必须等“凑满一桌”,先到的请求只能干瞪眼,用户感知到的首字延迟(TTFT)急剧上升。三个问题叠加,形成了一个恶性循环:等待攒批浪费资源 → 长尾拖累降低吞吐 → 排队恶化延迟体验 → 不得不买更多GPU填补窟窿。量化资源浪费程度,可用利用率公式:
包桌制的账越算越亏:客人等得久,灶台闲得慌,电费一分不少。正是这些触目惊心的浪费,让工程师们下定决心——必须把“凑桌”改为“流水”,让每一位客人的节奏独立起来。
- T_compute — 有效计算时间GPU真正在做矩阵乘法、生成token的时长,像厨师真正在掂勺炒菜的时间
- T_idle — 空闲等待时间GPU因攒批、等待慢请求、批间切换而闲置的时长,像后厨停火等客人的时间
- 分母 — 总耗时两者的和是系统运行总时长,利用率越低,说明每度电都花在“空烧”上
核心原理
流水席能做到永不停灶,靠的是一套精细的“翻台机制”,在推理领域称为迭代级调度(Iteration-level Scheduling)。传统调度以“完整的请求”为切换单位——一批跑完才轮到下一批;迭代级调度把切换粒度缩小到“一次解码迭代”:每算完一个token(相当于出一道菜),系统立刻环顾四周——哪些请求完成了?哪些新客人在等位?趁这一瞬间重新编排灶台上的批次。
请求插入(Request Insertion)是翻台的另一半。新请求到达后,只要当前批次还有空余的算力槽位,调度器就把它“加塞”进来,与老请求一同生成下一个token。注意,连续批处理并非毫无限制地塞人:它受显存容量和最大批大小约束,就像流水席的餐桌大小取决于餐厅面积。老请求吃完最后一口(序列完成,sequence completion),它的KV Cache——可以理解为这位客人吃了一半的“半成品食材”——会立即被回收,槽位重新开放给候补客人。
显存管理因此成为核心原理的暗线。每个请求在生成过程中都要保存历史token的键值缓存(KV Cache),相当于每位客人面前暂存的一碟碟菜品。静态批处理为每个请求预先分配“够用一整季”的显存,浪费惊人;连续批处理则按需分配、用完即收,让显存像流水席上的餐具一样高效流转。
流水席的精髓在于“名单是活的”。迭代级调度让每次小小的GPU前向传播都服务一组最新鲜的请求,灶台永远热气腾腾,这是连续批处理性能奇迹的发动机。
- B_t — 第t步的批集合当前解码迭代被送入GPU的请求集合,每走一步名单都可能变化,像流水席上每道菜端出时在座客人的集合
- r_i — 第i个请求一个具体的推理请求,比如用户输入的“写一首关于秋天的诗”
- Active(t) — 活跃请求集t时刻尚未完成、正在挨个生成token的请求,已完成者被剔除、新到达者被插入
关键算法
厨师长要管理一屋子客人,必须有一套明确的排菜规则。连续批处理的调度算法同样如此,最基础的是先来先服务(FCFS)——请求按到达顺序排队,先到先入批,公平且实现简单。但仅仅按序还不够,还需要解决“如何填坑”的问题:当某个请求完成腾出槽位,调度器要立刻从等待队列中取下一个请求补上,这叫连续填充(Continuous Fill),是保证“永不停灶”的关键动作。
在更复杂的生产环境中,队列往往不是单一FIFO就能搞定的。优先级队列(Priority Queue)允许我们给交互式请求(如聊天)更高权重,让它们插队到离线任务前面;抢占机制(Preemption)则处理更棘手的场景——当新来的高优请求急需显存,而低优请求已经在生成过程中,调度器可以抢占低优请求的显存,将其KV Cache暂存到CPU内存,等资源充足再恢复。这就像流水席上突然来了一位贵宾,服务员先把普通客人的半成品菜品端去保温柜暂存,腾出桌面给贵宾上菜。
整个调度循环可以用一个贪心判定来描述:每个迭代步,只要批大小未达上限且存在等待请求,就执行插入。
这些算法环环相扣:FCFS保证公平,连续填充保证高效,优先级队列体现业务偏好,抢占机制应对突发。厨师长手里的排菜手册并不复杂,但正是这套朴素的规则,让流水席在极端客流下依然有条不紊。
- Admit(r_i) — 准入判定函数输出1表示允许该请求入场,输出0表示它还得在候客厅等着
- |B_t| — 当前批的请求数量此刻灶台上正在服务的客人总数,像正在同时下锅的面碗数
- C_max — 批容量上限由显存大小和模型规模决定的硬约束,像餐厅消防条例规定的最大同时就餐人数
性能特征
换用流水席之后,小面馆的营业数据发生了戏剧性变化。学术界与工业界的实测(以Orca系统论文为代表)表明:相比静态批处理,连续批处理在相同条件下让系统吞吐量平均提升约2.8倍,在部分长尾明显的工作负载下甚至可以达到10倍以上的提升——这意味着以前需要10块GPU才能扛住的峰值流量,现在3块就绰绰有余。
延迟体验同样大幅改善。静态批处理中排在队首的请求要等攒批、等整批完成,首token迟迟出不来;连续批处理让请求“随到随做”,平均排队时间显著缩短,首字延迟(TTFT)和每token生成时间(TPOT)都更加稳定。显存利用率方面,由于请求完成即回收KV Cache、新请求按需分配,不再为每个请求预留一整块“可能用不完”的显存,整体显存开销大幅下降,同样的硬件能同时容纳更多并发请求。
这些优势还带来了规模化扩展的底气:吞吐量不再随并发增长而断崖式下跌,而是能够近似线性地承接更多请求。加速比可形式化为两种调度策略下总完成时间的比值:
营业数据说明一切:翻台率暴涨、等位时间骤降、食材(显存)浪费锐减。但这套流水席并非万能,它也有需要精心调教的地方——接下来的优化策略,就是给这套系统再次加压提速。
- T_static^total — 静态批处理总耗时从第一个请求进店到最后一位客人离店的完整时间,包含所有攒批等待和整批拖累
- T_continuous^total — 连续批处理总耗时同一批工作负载在流水席模式下的总完成时间
- 比值 S — 端到端加速比两者相除得到整体提速倍数,正是“换灶台”带来的红利
优化策略
流水席跑顺之后,厨师长开始琢磨:还能不能更快?第一板斧是PagedAttention(分页注意力)。它把显存管理从“给每位客人分一整桌”改成“分格子”——把KV Cache按固定大小的页(page)管理,像厨房冷藏柜里一格一格的小抽屉。需要就取一格,不需要就空着,彻底告别了静态预分配的碎片浪费。
第二板斧是投机采样(Speculative Decoding),它像让一位学徒先快速试菜,老师傅再尝一口确认。具体来说,一个小模型先草拟出未来若干token,大模型一次性并行验证草稿;如果验证通过,这些token就“免费”到手,省去了逐token生成的步骤。小模型出错时再回退重来,但整体期望收益为正,生成速度显著提升。
第三板斧是动态批大小(Dynamic Batch Size)——连续批处理虽然允许请求随意进出,但批大小依然是一个需要呼吸的变量。系统根据当前显存余量、请求到达速率动态调整批上限,高峰期多塞几个,低谷期少跑几步,避免始终用固定的“满桌”策略压垮显存。多卡部署时还要配置负载均衡(Load Balancing):让多个GPU都保持类似的忙碌程度,防止一块GPU累死、另一块闲死。显存节省的量化指标:
优化三板斧并不改变连续批处理的骨架,而是让它的肌肉更健壮、关节更灵活。PagedAttention化解了显存瓶颈,投机采样压缩了单请求耗时,动态批大小与负载均衡让系统在波动中依然稳如磐石。
- M_naive — 朴素预分配显存传统方案为每个请求预留最大可能长度所需的KV Cache空间,像给每人固定一整桌却只用到一角
- M_paged — 分页实际开销PagedAttention按实际请求逐页分配后的真实显存占用,像按需从冷藏柜取料的实际存货量
- 差值 — 节省量两者相减得到省下的显存,可用来容纳更多并发请求
案例分析
让我们看看这套流水席在真实世界中的样子。最典型的是vLLM框架——它在业界率先将连续批处理与PagedAttention结合,成为大模型推理的事实标准之一。假如你是一家AI公司的推理平台工程师,需要部署一个面向百万用户的对话服务:用户请求以每秒几十条的速率涌来,每条请求的回复长度从几十到几百token不等,长尾严重。使用朴素的静态批处理,GPU利用率不足三成,用户排队等首字超过10秒。
切换到vLLM后,生产部署流程变得清晰:拉起一个vLLM服务,配置好模型路径与最大并发数,它内部的调度器会自动执行连续批处理。请求到来即进队列,有槽即插入,完成即回收显存、立刻补新。典型问题也随之浮出水面——最常见的是显存不足(OOM)导致服务崩溃,这是因为并发请求过多、KV Cache暴涨。解决方案通常是两个方向:调低max_num_seqs(最大并发请求数),或者启用gpu_memory_utilization限制显存水位,给KV Cache留出呼吸空间。
另一个高频问题是“某个请求超长,把整批拖慢”。在连续批处理中,虽然长尾效应已被削弱,但单请求占用过多显存和算力仍会挤压同批伙伴。vLLM的调度器会限制单个请求的最大生成长度,超限即强制截断并回收资源——这对应的正是前面讲过的“抢占机制”。整个系统的状态可视为批集合的演化:
vLLM的实践印证了这套理论的价值:同样的A100/H100集群,搭载连续批处理后服务能力提升数倍,成本却几乎不变。所谓“典型问题+解决方案”,本质上都是调度与显存的博弈——而连续批处理站在赢的那一边。
- S_t — 当前批状态第t时刻正在GPU上服务的请求集合,像此刻正在就餐的客人名单
- R_new — 新到达请求本时间内新进店、被获准上桌的请求
- R_done — 已完成请求已经生成完整回答、可以结账离店的请求,需从名单中划掉
工程实践
理论再漂亮,落地还得看“经营看板”。部署连续批处理系统,首先要盯紧四个监控指标:吞吐量(每秒完成请求数)、TTFT(首字延迟)、TPOT(每token延迟)和KV Cache显存占用率。这四个指标分别对应流水席的“翻台率”“首道上菜速度”“出菜节奏”和“冷藏柜余量”。任何一项异常,都能帮你快速定位瓶颈:TTFT飙升说明攒批或排队严重,TPOT走高说明批太大或显存吃紧。
参数配置是日常调优的核心动作。vLLM中max_num_seqs控制最大并发请求数——相当于餐厅的座位数;max_num_batched_tokens控制单次前向传播最多处理的token数——相当于灶台火力上限。经验法则是:先把座位数设到显存允许的六至八成,再观察吞吐曲线,逐步上调直到TPOT出现拐点。遇到故障排查时,优先顺序是:先看显存占用有无OOM日志,再查请求排队长度是否持续堆积,最后检查大模型权重和输入长度是否存在极端值。
最佳实践可以总结为:监控先行、参数渐进、压测验证。上线前用真实流量形态做压测,记录吞吐-延迟曲线,找到“拐点”在哪里,让系统始终运行在高吞吐且延迟可控的甜点位。延迟的中位数可用分位数公式衡量:
经营看板上的每个数字都在告诉你流水席是否健康。连续批处理不是“装好就完事”,它需要持续的调优与监控。掌握了这份实践手册,你就能让推理系统在真实生产环境中稳定地保持高吞吐、低延迟,让每一分GPU算力都物有所值。
- l_i — 第i个请求的延迟从请求到达系统到首字(或完整回答)返回的耗时,像每个包间的上菜时间
- n — 请求总数统计窗口内观测到的全部请求数量
- median — 中位数把延迟从小到大排列取中间数,不受极端值干扰,比平均值更能反映典型体验
AI 应用场景
在线对话与AI助手服务
阶段:模型推理部署与性能优化
解决的问题:传统静态批处理下,对话请求到达时间随机、回复长度参差不齐,GPU要么等攒批空转,要么被长句请求拖累整批,用户等待首字超过10秒,体验极差。连续批处理让每个用户请求独立进出批次,新消息“随到随做”,GPU吞吐量提升数倍,对话服务的并发承载能力大幅增强。
具体案例:某SaaS公司基于vLLM部署Qwen系列对话模型,高峰期每秒涌入50+请求,回复长度从20到500 token不等。启用连续批处理+PagedAttention后,吞吐量从原来的120 req/s提升至400 req/s,P50首字延迟从2.8秒降至0.6秒,GPU集群从8卡缩减至4卡。
代码补全与生成工具
阶段:低延迟在线推理服务
解决的问题:代码补全要求极低的用户感知延迟,静态批处理每次都要凑批或等待整批完成,无法满足“打字即补全”的交互需求。连续批处理配合投机采样(小模型草稿+大模型验证),让补全请求几乎立即开始生成,同时保持高吞吐。
具体案例:某IDE插件背后的代码生成后端,使用中型代码模型提供后缀补全。通过连续批处理让多用户请求共享GPU,再叠加投机采样将单token生成延迟从80ms压缩到35ms,用户补全接受率提升了20%。
离线批量推理任务
阶段:批量数据处理与内容生产
解决的问题:大规模评测集打分、批量文本摘要、数据清洗等离线任务,请求量大且对延迟不敏感,核心诉求是最大化吞吐、摊薄算力成本。连续批处理让这类任务在满载GPU上像工厂流水线一样运转,显著缩短整体耗时。
具体案例:某内容平台每天需要对十万篇文章做标题生成,采用连续批处理架构后,单卡A100的日处理量从2万篇提升至5万篇,整体算力支出下降约60%。
Python 演示
"""模拟静态批处理与连续批处理, 对比完成时间与吞吐量"""from collections import deque class Request: def __init__(self, req_id, arrival, tokens=60): self.id = req_id self.arrival = arrival self.remaining = tokens self.finish_at = None def is_done(self): return self.remaining == 0 def step_request(req, cur_time): if req.remaining > 0: req.remaining -= 1 if req.remaining == 0: req.finish_at = cur_time def simulate_static(requests, batch_size=4): pending = deque(sorted(requests, key=lambda r: r.arrival)) ready = deque() in_flight = [] t = 0 while pending or ready or in_flight: while pending and pending[0].arrival <= t: ready.append(pending.popleft()) if not in_flight and len(ready) >= batch_size: for _ in range(batch_size): in_flight.append(ready.popleft()) elif not in_flight and ready and not pending: while ready: in_flight.append(ready.popleft()) if in_flight: for r in in_flight: step_request(r, t) in_flight = [r for r in in_flight if not r.is_done()] t += 1 return max(r.finish_at for r in requests) def simulate_continuous(requests): pending = deque(sorted(requests, key=lambda r: r.arrival)) active = [] t = 0 while pending or active: while pending and pending[0].arrival <= t: active.append(pending.popleft()) for r in active: step_request(r, t) active = [r for r in active if not r.is_done()] t += 1 return max(r.finish_at for r in requests) def main(): requests = [ Request(i, arrival=(i // 2) * 2, tokens=40 + (i % 3) * 10) for i in range(24) ] static_time = simulate_static(requests, 4) continuous_time = simulate_continuous(requests) print("静态批处理耗时: %d 时间步" % static_time) print("连续批处理耗时: %d 时间步" % continuous_time) print("吞吐量提升: %.2f 倍" % (static_time / continuous_time)) if __name__ == "__main__": main()
pending = deque(sorted(requests, key=lambda r: r.arrival))把所有请求按到达时间排成队列,像客人按到店顺序取号while pending and pending[0].arrival <= t:每个时间步检查是否有新请求到达,模拟客人陆续进店if not in_flight and len(ready) >= batch_size:静态批处理的核心:当前批为空且攒够4个才开始,否则空等in_flight = [r for r in in_flight if not r.is_done()]批次结束后移除已完成请求,腾出槽位for r in active: step_request(r, t)连续批处理每个时间步让所有活跃请求各生成一个tokenreturn max(r.finish_at for r in requests)取最后一个请求完成的时间,即系统总完成时间
常见误区
误区既然是“随到随做”,那我是不是可以把并发请求数设到无穷大,反正系统会自动塞?批大小越大,吞吐肯定越高,何乐而不为?
正解连续批处理只是突破了“凑齐整批”的限制,但批容量仍有硬性约束:显存容量决定KV Cache最多能装多少请求,算力决定每个迭代多塞请求会拉长单次延迟。批过大会导致显存溢出(OOM),或让每个token的生成时间(TPOT)暴涨,吞吐曲线存在拐点,过了拐点反而下降。
为何常见:人们看到“动态插入”就直觉地以为所有限制都消失了,忽略了物理资源上限始终是悬在头上的天花板。
误区动态批处理不就是每隔一段时间调整一下批大小吗?跟连续批处理有什么区别?我觉得是同一个东西。
正解动态batch size通常指在批与批之间调整批的规模,批次内部的成员保持不变;而连续批处理的精髓是迭代级调度——每个解码步都重新决定批成员,请求可以在任意迭代插入或退出。真正的区别在于“调度粒度”:一个是批级调整,一个是请求级甚至token级的实时编排。
为何常见:两者都涉及“批的大小在变化”,表面相似,容易混淆深层机制,只有理解迭代级调度才能看到本质差异。
误区吞吐量是上去了,但单个用户的请求肯定还是得排队等前面的处理完,延迟不会有什么变化吧?
正解连续批处理同样显著改善了延迟。静态批处理中请求要等“凑够一桌”才能开始,排队时间可能长达数秒;连续批处理只要有空闲槽位立刻入场,首字延迟(TTFT)大幅下降。此外,短请求不再被长请求“陪绑”,完成时间更为稳定,长尾延迟体验明显改善。
为何常见:人们常把“吞吐”与“延迟”视为跷跷板的两端,忽略了连续批处理在减少无效等待上双管齐下,两项指标其实是同向改善的。
误区vLLM那么快全靠PagedAttention省显存,连续批处理只是锦上添花,有没有都行。
正解两者是不同层面的机制,缺一不可。连续批处理解决的是“如何让GPU时刻满负荷工作”的调度问题,PagedAttention解决的是“如何让显存装下更多请求”的空间问题。没有连续批处理,即使显存分页再高效,GPU仍会在攒批和长尾等待中空转;没有PagedAttention,连续批处理则很快因KV Cache膨胀而触顶。
为何常见:PagedAttention的名字响亮、效果直观,容易被记住;而连续批处理作为后台调度机制不那么显眼,却恰恰是吞吐红利的最大贡献者。
面试题
Q1. 静态批处理的主要弊端是?
- A.攒批时GPU空转,且批次内互相拖累← 正确答案
- B.批内请求互相干扰,降低输出质量
- C.无法利用GPU并行计算能力
- D.不支持流式输出只能一次性返回
答案:A。静态批处理必须攒满一批才启动,攒批期间GPU算力闲置;批内不同请求长度不一,短的被长的拖住,造成双重浪费。B、C并非静态批处理的本质问题,D则与实际不符。
Q2. 连续批处理的核心调度单位是什么?
- A.整个批次一起开始和结束
- B.单个请求的单个生成步骤← 正确答案
- C.完整的模型前向传播
- D.单个请求的完整生命周期
答案:B。连续批处理采用迭代级调度,在每次解码迭代(生成一个token)时动态决定批成员,因此核心调度单位是“单个请求的单步生成”。A是静态批处理的特征,D是端到端任务周期,C过于笼统。
Q3. 以下哪些属于连续批处理的优势?
- A.提升系统整体吞吐量← 正确答案
- B.允许请求动态插入批中← 正确答案
- C.降低首字延迟和排队时间← 正确答案
- D.彻底消除显存占用
答案:ABC。连续批处理让GPU不再等待攒批,吞吐量大幅提升;请求可随时插入空闲槽位;排队等待减少使首字延迟下降。D过于绝对,显存占用只能优化不能消除。
Q4. 长尾效应对静态批处理的直接影响是?
- A.批内最短序列决定整批速度
- B.批内最长序列拖住整批生成← 正确答案
- C.所有请求独立且互不影响
- D.批次越大尾部延迟反而越小
答案:B。静态批处理中整批同步推进,生成速度受批内最长序列约束,短请求完成早也得陪着跑完,造成GPU算力浪费。A方向反了,C是连续批处理的理想状态,D与经验事实相悖。
Q5. 关于迭代级调度,下列说法正确的是?
- A.每个解码步动态决定批成员← 正确答案
- B.已完成请求立即腾出槽位← 正确答案
- C.新请求只能在批间间隙加入
- D.每个迭代都执行一次前向计算← 正确答案
答案:ABD。迭代级调度在每次前向计算前重组批成员,请求完成的瞬间回收显存、释放槽位,新请求可在任意迭代插入。C描述的“批间间隙”是静态批处理的限制。
Q6. PagedAttention 的核心作用是?
- A.将KV Cache按页管理以减少浪费← 正确答案
- B.把模型权重分页存储到磁盘
- C.提高注意力计算的数值精度
- D.用CPU内存完全替代GPU显存
答案:A。PagedAttention把KV Cache切分为固定大小的页,按需分配与释放,显著降低显存碎片和预分配浪费。BCD与PagedAttention的实际机制不符。
Q7. vLLM 实现连续批处理依赖哪些机制?
- A.迭代级调度器← 正确答案
- B.PagedAttention 显存管理器← 正确答案
- C.投机采样草稿模型
- D.等待队列与槽位管理← 正确答案
答案:ABD。vLLM的核心是迭代级调度+PagedAttention+请求队列管理,三者配合实现了高效的连续批处理。投机采样是可选的加速手段,并非连续批处理本身的组成部分。
Q8. 批内某请求因超长被强制截断时,调度器应如何处理其KV Cache?
- A.立即释放并让出新槽位← 正确答案
- B.保留至本批结束再释放
- C.迁移至CPU侧长期保存
- D.随机丢弃部分页避免碎片
答案:A。强制截断与正常完成在资源回收上等价——请求不再产生token,其KV Cache应立即释放,槽位供新请求使用。B拖延了资源回收,C长期保存没有意义,D随机丢弃会造成缓存损坏。
Q9. 以下哪些工程指标用于评估连续批处理系统?
- A.TTFT 首Token延迟← 正确答案
- B.TPOT 每Token生成时间← 正确答案
- C.KV Cache 显存利用率← 正确答案
- D.模型参数量大小
答案:ABC。TTFT反映用户首字等待体验,TPOT反映生成节奏,KV Cache利用率反映显存健康度,三者是连续批处理调优的核心监控指标。D模型参数量是静态属性,不随调度策略变化,不用于评估系统运行状态。
Q10. 投机采样为什么能加速推理?
- A.小模型草稿被大模型并行验证← 正确答案
- B.降低生成质量以换取速度提升
- C.跳过注意力计算直接输出结果
- D.用更多GPU并行减少计算量
答案:A。投机采样让小模型先草拟多个token,大模型一次前向并行验证,验证通过的token无需逐一生成,从而压缩有效延迟。B是错误的,投机采样理论上有界不损失质量;C和D都不是其工作原理。