“川味居”是高新区最火的一家川菜馆。每天中午,后厨灶台前挤满了服务员的催单声:“李师傅,3 号桌的水煮鱼!”“李师傅,7 桌的麻婆豆腐!”老办法是一单一炒:开火、倒油、下料、翻勺、出锅——灶台有一半时间在空烧。直到李师傅想明白一个道理:与其一单一单炒,不如把同时段下的单攒成一锅。一锅水煮鱼的油温,可以同时汆熟三份鱼片;同一把勺,可以同时翻四份宫保鸡丁。于是他在出菜口放了几个托盘,凑满四盘就一起下锅;若两分钟还没凑满,也先开火,免得客人饿急。这就是“批处理”:用一点点等待,换来灶台(显卡)的满负荷运转。批量推理(Batching),正是大模型服务端把“一单一炒”改成“整托下锅”的工程艺术。
对 AI 从业者来说,Batching 是决定大模型服务吞吐与成本的核心工程杠杆。掌握动态批处理、队列、显存与连续批处理,你就能用同样的显卡数量服务 3-5 倍的流量,这是推理系统工程师的核心竞争力。
可视化演示
动态演示批量推理Batching工程的核心机制,通过基础/核心/应用/扩展四种模式展示关键概念与交互流程。
本节配有交互动效(进入视口后自动加载,约 3KB)。
批量推理Batching工程:在推理服 在推理服务端处理并发请求时的批 请求队列管理与优先级调度策略 核心机制可视化 批量推理Batching工程整体架构与关键组件
动态批处理
李师傅的秘诀其实就一句话:别让锅闲着。以前一单一炒,锅在等菜、菜在等人,燃气白白烧。现在他在出菜口放了托盘,服务员把新单放进同一个托盘,凑满四盘就喊一声“下锅!”。如果两分钟还没凑满,也先开火——菜可以少,锅不能空。这个“凑满四盘”和“两分钟”就是批处理的两个旋钮:一个管上限,一个管等待。
大模型推理服务面临的困境一模一样。每个用户请求过来,GPU 都要重新加载一遍上百亿参数的模型权重,执行一次前向计算。如果来一个算一个,GPU 就像那口空烧的锅,利用率常常不到 20%。动态批处理(Dynamic Batching)的做法是:把到达时间接近的请求收集起来,凑成一个批次(Batch)一起送进模型。多条请求共享同一次权重加载和更稠密的矩阵运算,吞吐立刻翻几倍。
工程上这套机制依赖两个关键参数:max_batch_size 规定一锅最多几盘,防止单批过大导致显存爆掉、延迟失控;max_wait_ms 是窗口倒计时,超过这个时间还没凑满也必须下发,防止请求“饿死”在队列里。两个条件任一满足,调度器就把当前排队中的请求整批送入模型。模型内部,一批请求会经历两个阶段:先把输入一起算一遍(预填充 Prefill),再一个 token 一个 token 地并行生成回答(解码 Decode)。批处理之所以能提速,正是因为解码这一步的耗时不会随批大小线性上涨。
最后回到厨房:一锅四盘菜的秘诀就在于油温同一份、火候同一灶、翻勺同一遍。动态批处理做的正是这件事——用可以接受的等待,换取灶台永远满负荷。记住,批处理从来不是免费的午餐,而是一场“延迟换吞吐”的交易,交易是否划算,要看接下来的每一个工程细节。
- 预填充阶段开销
t_prefill(B)是批内所有输入 token 一次性前向计算的时间。它随 B 增长但远慢于线性——因为模型权重只需要加载一次,多条输入共享同一份权重矩阵运算。 - 最长序列长度
L_max是批内所有请求目标输出长度的最大值。解码过程逐 token 推进,整批必须等最慢的那条生成完,这正是批处理延迟的代价来源。 - 解码单步耗时
t_decode(B)是每生成一个 token 的耗时。由于 B 条序列的 token 在同一个 Transformer 前向中并行计算,显存带宽被摊薄,单 token 成本随 B 下降。 - 对照串行基线若 B 条请求完全串行,总耗时约为每条请求各自的预填充加解码之和。批处理把这一堆线性累加压缩成“一次预填充 + 一条最长解码路径”,这就是收益来源。
请求队列管理
川味居门口有个叫号台。中午十二点,客人像潮水一样涌进来,二十张单子同时压在出菜口;下午三点,又冷清得只有两桌。叫号小姐姐手里攥着一沓排号单:先来的先安排,VIP 客人可以往前挪,等超过十五分钟的客人会送一碟泡菜安抚。要是队伍排到了大门外,就得客气地请客人改天再来——这叫限流。
推理服务的请求到达同样忽高忽低,绝不会匀速。生产系统中,请求必须先进入一个请求队列(Request Queue),由调度器从队列中取请求来组批。队列是请求与 GPU 之间的缓冲层:没有它,突发流量会直接把服务打崩;有了它,GPU 可以在低峰期“多等等攒一锅”,高峰期“凑满就赶紧下锅”。队列设计有三个核心维度:结构(FIFO 主序还是按优先级排列)、超时(排队太久直接淘汰并返回兜底结果)、长度上限(队满时对新请求做背压/拒绝,保护服务本身)。
排队这件事有一个非常优雅的数学定律,叫利特尔法则(Little's Law)。它把系统里最重要的三个指标串在了一起:平均队长、到达率和平均等待时间。
叫号台的本质是一个“蓄水池”:它不产生新客人,但让客流变得可管理。请求队列在推理服务里扮演的正是这个角色——当流量洪峰到来时,队列帮你稳住阵脚,让动态批处理有“货”可凑、让 GPU 有活可干。但别忘了,蓄水池的水位每高一寸,等位客人的脸色就难看一分。
- 平均队长系统内正在排队和正在处理的请求总数。在批推理服务里,它就是出菜口托盘上攒着的“待下锅订单”数量。
- 到达率单位时间进入队列的新请求数。饭点突增时 λ 飙升,这就是突发流量。
- 逗留时间一个请求从入队到处理完成的总耗时,包含排队等待加上批处理时间,也就是客人的“从等位到上菜”。
- 三者关系稳态下三者严格满足等式。它告诉你:想让 W 降下来,要么减小 L(限流或扩容),要么接受 λ 不变时两者必然联动。这对设定队列长度上限有直接指导意义。
显存占用控制
川味居后厨有一台双开门保鲜冰柜,容量有限得精打细算。每道半成品菜(正在生成中的回答)都要占一个保鲜盒:鱼片腌好了放一层,宫保鸡丁半成品放一层。问题在于,这些盒子是随着做菜过程不断长大的——菜越做越多,盒子越占越大。冰柜总共那么大,还要留位置给备料(模型权重)和案板(激活值)。盒子用完不腾,新菜就没处放;盒子大小不一放多了,中间碎成一小块一小块的空隙,大盒子根本塞不进去——这就是碎片。
大模型推理时,每一条请求的 K/V Cache(注意力缓存的 Key 和 Value 张量)会随着 token 生成不断增长,是显存消耗的绝对大头。如果只按输入长度估算显存,上线必炸——因为生成过程才是显存杀手。工程上要做显存预算(Memory Budget):总显存被划分为模型权重、激活值、KV Cache 和预留余量四块,任何一块超限都会 OOM 崩掉整个服务。现代推理框架还会用 PagedAttention 这类技术,把 KV Cache 切成小块分页管理,像操作系统管理内存一样消除碎片、按需分配。
要估算 KV Cache 的占用量,可以用下面这个公式:
保鲜盒规划得好,灶台才能同时开很多锅;显存规划得好,batch 才敢往大开。李师傅每天都在冰柜门上贴一张预算表,哪格放什么、剩多少余量,一目了然。推理服务的显存水位,也需要这样一张随时可查的“冰柜地图”——这是批处理能安全跑起来的地基。
- 批大小当前批内请求数。队列越长、锅越大,保鲜盒占位就越多,这是唯一可以直接调控的变量。
- 平均序列长度解码过程中每条序列的长度持续增长,因此 L̄ 必须按平均生成长度或上限 max_model_len 来估算,而不是只看输入 token 数。
- 层数与隐藏维度D 是 Transformer 层数,H 是每层隐藏维度。模型越大,每 token 每层要缓存的元素越多,KV Cache 随模型规模指数级膨胀。
- K 与 V 双份注意力计算同时需要 Key 和 Value 两组缓存,所以乘第一个 2。
- 精度字节数FP16 半精度下每个元素占 2 字节,再乘一次,最终得到以字节为单位的显存占用。
批大小自动调整
李师傅练就了一项本事:看客流调锅数。饭点门外排长队,他一锅炒八盘;晚上快打烊,一锅炒两盘就出锅。怎么调?他靠试——上次加了量客人没投诉,说明锅还能更大;上次等太久被投诉,赶紧收一收。同时他还留了个心眼:一次只调一点点,绝不一上来就从两盘跳到八盘,免得锅气全乱。
固定 batch 大小没法应对波动的流量。自适应批大小(Adaptive Batch Size)算法实时观察三个信号:队列水位(排队人数)、延迟与 SLA 的距离(客人有没有等急)、显存水位(冰柜还剩多少)。当排队水位高于目标值时,说明“货多锅小”,应该加大批次;当延迟超标或显存吃紧时,就减小批次。为了防止抖动,调整幅度要小、方向要准,并且随时准备回头。
这个“试探-调整”的过程可以用一个简洁的增量公式描述:
自适应批大小等于把李师傅的“手感”变成了仪表盘上的量化规则。它不需要人盯着监控面板手动改参数,而是让系统自己像经验丰富的厨师长一样,在客流变化时提前调整锅的容量。这也是从“能跑”到“跑得好”的关键一步。
- 当前批大小本轮的“锅容量”,是我们唯一要动态调节的控制变量。每次调整都基于上一轮的结果。
- 步长单次调整的幅度。η 太小反应慢,流量洪峰来了跟不上;η 太大系统震荡,吞吐忽高忽低像过山车。
- 水位偏差方向
Q_t - Q*大于 0 说明队列越排越长,该加大批次;小于 0 说明系统空闲,该减小批次降低延迟。sign 只取正负号,避免单次偏差过大导致过度反应。 - 更新与保护乘上步长后还要用 clip 裁剪到安全区间,保证显存不超预算、吞吐不掉到地板以下。
连续批处理
老办法有个尴尬场景:一锅六盘菜,五盘三分钟就出锅了,最后一盘佛跳墙要炖半小时。其余五盘在出菜口晾着,锅也占着,谁也不能动。李师傅被这个场景折磨了很久,直到他换了思路——哪盘好了立刻端走,腾出的锅位马上放新菜,不等那盘佛跳墙。锅永远满载,翻台率立刻上了一个台阶。这就是“连续批处理”:别再等最慢的那盘。
在传统静态批处理(Static Batching)中,一个 batch 内所有序列同步解码,直到最长的那条序列生成完毕,整批才一起释放。序列长短差异越大,短序列的空转浪费就越严重,这种浪费叫“气泡”(Bubble)。连续批处理(Continuous Batching,也叫迭代级调度 Iteration-level Scheduling)改变了规则:在每个解码迭代结束时检查所有序列,完成的序列立刻离开批次、释放显存槽位,新请求立刻补进来。GPU 的每一个迭代都近乎满载。
批次利用率可以用下面的公式量化:
连续批处理犹如流水线出菜,不设“齐了才开席”的门槛,灶台每一秒都在替餐厅赚钱。如今主流的推理框架(vLLM、TensorRT-LLM 等)都默认启用这种调度方式,它把批处理的收益又抬高了一截——但这并不意味着前面的动态批处理和队列管理可以省略,它们负责“组队”,连续批处理负责“在队内高效运转”,是前后台的关系。
- 批次大小同一时刻并行处理的序列数,也就是同时占着锅的菜盘数。
- 实际序列长度每条请求真正生成的 token 数,长短不一——有的客人只点一道快手菜,有的点佛跳墙。
- 最长序列静态批处理必须等它完成才释放整个批次,所有短序列都在为它陪跑。
- 利用率分子是有效计算量,分母是占坑总容量。η 越接近 1 越好;若长短悬殊,η 会显著小于 1,说明静态批处理的浪费有多大。
生产部署实践
新餐厅开业前,李师傅做了三件事:提前一天把高汤熬好、配菜备齐(模型加载与预热);把停水停电的应急预案写在厨房墙上(故障恢复);开业头三天只接待预定客人,慢慢放量(限流压测)。没有这些准备,开业当天就是灾难片现场。生产环境部署批推理服务,道理完全相同。
选对框架是第一步。vLLM、TensorRT-LLM、Text Generation Inference(TGI)都内置了动态批处理和连续批处理能力,没必要从零造轮子。第二步是配参:max_num_seqs 控制最大并发序列数,gpu_memory_utilization 控制显存占用比例(通常留出 10%-20% 余量),max_model_len 直接决定 KV Cache 预算上限。第三步是故障恢复设计:请求排队超时要能优雅降级(返回兜底回答或建议稍后重试),后端实例 OOM 时要有熔断机制,不能把整个网关拖垮。
容量规划需要回答一个问题:单实例到底能扛多少 QPS?这要通过压测找到“最优批大小”来回答:
开业前的试营业,就是为了找到“一桌最多坐几个人、后厨一次能接几锅”的答案。生产部署没有玄学:选好框架、配好参数、做好预案、压测定容,四步走完,服务才能在大流量面前站得住脚。李师傅常说,后厨的从容,都是开业前流过的汗换来的。
- 最优批大小压测曲线上的吞吐拐点与延迟 SLA 边界,取两者中更靠前的一个作为 B_opt。再大,延迟就超线了。
- 单批耗时该批大小下端到端时间,包含排队等待、预填充阶段和解码阶段三部分。压测时测的是真实分布,不是平均值。
- 单实例吞吐批大小除以单批耗时,得到理论最大 QPS。乘上实例数就是集群总容量,这是容量规划的核心依据。
- SLA 约束所有配置都以 P99 不超过阈值为硬前提。P99 超标,哪怕吞吐再高也要调小 B_opt——客人的耐心是有限的。
性能评估调优
周末打烊后,李师傅对着账本复盘:翻台率(吞吐量)、等位时长(延迟)、食材成本(成本效率)。他发现周六翻台率高但等位也长,说明“锅数”不够用;周中翻台率低,说明凑单策略太贪——单子少还死等满锅,客人全跑了。于是他把窗口参数调小,下周报表立刻改善。数据不会骗人,但前提是你得把数据记下来。
评估批推理系统,核心指标有四类:吞吐量(每秒完成请求数 req/s 或每秒产出 token 数)、延迟(首 token 时延 TTFT、单 token 时延 TPOT、P99 尾延迟)、显存水位、成本效率。特别要注意,批处理是用延迟换吞吐的交易,所以“吞吐翻倍、P99 翻三倍”这种结果并不值得庆祝——必须用 SLA 作为约束来评价。监控面板上,吞吐的绿色曲线和 P99 的红色曲线往往呈镜像走势,最优配置就在两线交汇点附近。
成本效益的量化,是评判批处理策略值不值的最终标准:
只有把账算明白,才知道批处理省下的燃气够不够给客人送果盘。李师傅的账本记录着每一种调料的花销,你的监控面板也应该记录着每一个 token 的成本。性能调优不是凭感觉拧参数,而是看报表、找瓶颈、做假设、再验证的循环——数据是厨师长最可靠的舌头。
- 硬件成本GPU 单位时间成本,包含采购摊销、电力和机房费用。这是分母的“单价”。
- 运行时长统计周期内服务持续运行的时间。跑得越久,固定成本摊得越薄。
- 产出 token 数周期内所有请求生成的 token 总量,包括预填充阶段的输入 token 和解码阶段的输出 token。
- 单位成本三者相除得到每个 token 的平均成本。对比不同批处理策略时,谁的 C_token 低,谁就更划算——这既是内部调优的标尺,也是对外定价的依据。
AI 应用场景
企业内部统一 LLM API 网关
阶段:推理服务部署与流量治理
解决的问题:多个业务线(客服、写代码助手、文档摘要)各自独立部署大模型服务,GPU 利用率往往不到 20%,且流量高峰互相错开、无法互补。通过统一网关汇聚所有请求,用动态批处理把不同业务的请求混批,用请求队列做优先级调度(客服请求优先于批量任务),整体吞吐可提升 3-5 倍。
具体案例:某互联网公司的推理平台将 6 个业务线的 12 个独立服务收敛为 2 个共享推理集群,统一入口加动态批处理,GPU 数量从 40 块降到 16 块,P99 延迟反而因为队列治理更稳定。
离线批量内容生成
阶段:数据生产与离线任务调度
解决的问题:广告文案改写、商品摘要生成、数据标注预标注等任务没有实时交互需求,传统做法是逐条调用模型,慢且贵。这类场景适合“超大 batch + 长窗口”策略:把窗口拉到秒级、批大小顶到显存预算上限,牺牲少量等待换取接近满载的吞吐。
具体案例:某电商团队需要在夜间批量生成 100 万条商品摘要。他们用离线批处理脚本配合连续批处理框架,设置 max_batch_size=64,窗口 2 秒,整夜跑完,每千 token 成本比在线调用降低约 70%。
多租户共享 GPU 的显存隔离
阶段:资源管理与多租户调度
解决的问题:不同团队共享同一个 GPU 集群时,一个租户的长序列请求(比如超长文档分析)可能瞬间吃光全部 KV Cache 显存,导致邻居租户请求 OOM。通过显存预算分配、自适应批大小和队列水位监控,把每个租户的显存上限锁死,同时动态调整批大小适配各自流量。
具体案例:某大模型平台用显存预算配置为每个租户划定 KV Cache 比例,配合 PagedAttention 的分页管理,将多租户场景下的 OOM 故障率从每周 10+ 次降到接近 0。
Python 演示
"""动态批处理调度模拟器:用窗口和最大批大小两个旋钮控制批次划分"""from dataclasses import dataclassfrom typing import List @dataclassclass Request: req_id: int arrive_ms: float gen_len: int = 32 class DynamicBatcher: """一锅一锅地接单:凑满 max_batch 或窗口到期就下锅""" def __init__(self, max_batch: int = 4, window_ms: float = 50.0, token_ms: float = 2.0): self.max_batch = max_batch self.window_ms = window_ms self.token_ms = token_ms self.batch: List[Request] = [] self.stats: List[tuple] = [] def push(self, req: Request, now_ms: float) -> None: self.batch.append(req) self._maybe_flush(now_ms) def _maybe_flush(self, now_ms: float) -> None: if not self.batch: return first_arrive = self.batch[0].arrive_ms window_hit = (now_ms - first_arrive) >= self.window_ms if len(self.batch) < self.max_batch and not window_hit: return self.flush(now_ms) def flush(self, now_ms: float) -> None: batch = self.batch self.batch = [] longest = max(r.gen_len for r in batch) process_ms = longest * self.token_ms finish_ms = now_ms + process_ms for r in batch: latency = finish_ms - r.arrive_ms self.stats.append((len(batch), process_ms, latency)) def main(): batcher = DynamicBatcher(max_batch=4, window_ms=50) times = [0, 8, 16, 24, 60, 66, 72, 78, 120, 130] reqs = [Request(i, t) for i, t in enumerate(times)] now = 0.0 for r in reqs: now = r.arrive_ms batcher.push(r, now) batcher.flush(now + 1) count = len(reqs) total_lat = sum(s[2] for s in batcher.stats) print(f"共 {count} 个请求,划分为 {len(batcher.stats)} 个批次") for i, (size, process, _) in enumerate(batcher.stats, 1): print(f"第 {i} 批:批大小 {size},批处理耗时 {process}ms") print(f"平均端到端延迟:{total_lat / count:.1f} ms") if __name__ == "__main__": main()
self.batch: List[Request] = []当前正在“凑单”的托盘,新请求先放进来攒着self._maybe_flush(now_ms)每次有新请求到达都检查一次:该不该下锅?window_hit = (now_ms - first_arrive) >= self.window_ms窗口超时触发:第一个请求等太久,哪怕没凑满也得开火if len(self.batch) < self.max_batch and not window_hit: return两个触发条件(满批、超时)都没满足时继续攒单longest = max(r.gen_len for r in batch)一批菜里最费火的那道决定出锅时间,即批处理耗时由最长序列决定latency = finish_ms - r.arrive_ms端到端延迟包含排队等待和处理时间,是评估批处理策略的关键输出
常见误区
误区batch size 开到显存能塞下的最大值不就行了?反正 GPU 并行算得过来,批越大吞吐越高。
正解批大小与吞吐不是单调关系。批增大时,单批耗时(尤其解码阶段)随之增大,KV Cache 显存线性上升,P99 延迟快速恶化。吞吐曲线通常先升后降,存在一个最优拐点。正确做法是压测扫点,找到“吞吐拐点”与“延迟 SLA 边界”中更靠前的那一个。李师傅一锅炒二十盘的后果,就是前面十盘全凉了——锅的容量要配得上菜的性质。
为何常见:单看公式 T = B / t_batch 时,B 在分子,直觉上觉得 B 越大越好,忽略了 t_batch 也在变大,而且变大得越来越快。
误区动态批处理不就是等 50ms 再一起发吗?设置一个固定延时窗口就够了。
正解固定窗口只是触发策略之一,而且是效果最差的那一种。真正的动态批处理是“窗口超时、批次满员、强制冲刷”三类条件任意满足即下发;更强的实现还会结合队列水位、显存余量动态调节窗口时长和批大小上限。固定窗口在流量稀疏时白白增加延迟,在流量洪峰时又来不及扩容,必须配合满批触发才能兼顾吞吐与延迟。
为何常见:大多数教程和简化的示例代码都用“等一段时间再发”来演示动态批处理,让人误以为窗口是唯一机制。
误区模型 7B 参数大概 14GB,输入最长 2048 token,算下来没超显存啊,怎么一上线就 OOM?
正解漏掉了 KV Cache 随解码动态增长这个大头。每条请求每生成一个 token,KV Cache 就要追加 2 × D × H × 2 字节;batch 内所有请求累计起来非常可观,且预填充阶段的激活值也会瞬时暴涨。正确的预算公式应为:模型权重 + 激活值峰值 + 2 × B × L_max × D × H × 2 字节 + 预留余量。李师傅的冰柜里,备料和半成品菜是分格管理的,每一格都要算清楚。
为何常见:KV Cache 不像模型权重那样“看得见摸得着”,是运行时动态分配的,新手容易忽略它随生成的增长性。
误区vLLM 的 continuous batching 不就是动态批处理换了个名字吗?反正都是攒一批再算。
正解两者处于不同层级。动态批处理在“请求进入 batch 之前”做决策,解决的是攒够什么条件才组批;连续批处理在“batch 内部迭代中”做决策,解决的是每一步解码后哪些序列完成、能否释放槽位补新请求。序列长度参差时,连续批处理能把利用率 η 从 0.5 提升到接近 1。它们是互补的前后台关系,不是同义反复。
为何常见:两者都带"batch"字样,且框架文档常把调度层(动态批处理)和执行层(连续批处理)混着介绍,读者容易混淆层级。
误区压测报告显示吞吐从 500 req/s 涨到 2000 req/s,翻了四倍,直接上线!
正解批处理本质是“用延迟换吞吐”的交易。吞吐翻四倍时,P99 可能从 300ms 涨到 3s,首个 token 的等待时间也大幅变长,用户体感极差。生产上线必须同时盯三类指标:吞吐、延迟(TTFT/TPOT/P99)、显存水位,并以前置 SLA 为硬约束。只看吞吐的后果是上线后用户投诉、半夜回滚——就像只看翻台率、不看等位时长的餐厅,迟早被差评淹没。
为何常见:吞吐是最容易量化和汇报的指标,而延迟分布和 SLA 需要额外埋点与统计计算,容易被图省事的团队跳过。
面试题
Q1. 动态批处理中,以下哪一项不是触发批次下发的典型条件?
- A.队列中请求数达到最大批大小
- B.首个请求等待时间超过最大窗口
- C.GPU 利用率下降到阈值以下← 正确答案
- D.调度器主动强制冲刷当前批次
答案:C。动态批处理的触发条件围绕“满批”和“超时”展开:队列满员、窗口超时、强制冲刷都常见,而 GPU 利用率下降不会触发组批,恰恰相反,组批是为了提升利用率。这就像后厨不是因为锅凉了才开火,而是因为托盘满了或客人等久了。
Q2. 关于利特尔法则 L = λW,以下理解正确的是?
- A.延迟越低则吞吐一定越高
- B.到达率翻倍则等待时间减半
- C.稳态平均队长等于到达率乘逗留时间← 正确答案
- D.队长超过服务能力后请求开始丢失
答案:C。利特尔法则说的是稳态下 L、λ、W 三者满足乘法关系,C 是其标准表述。A 与 B 都颠倒了因果,延迟与吞吐的取舍关系取决于 SLA 约束而非简单反比;D 描述的是队列溢出后的背压现象,是超限后的结果而非法则本身。
Q3. 在 KV Cache 显存估算公式 M = 2 × B × L × D × H × 2 字节中,第一个"2"代表什么?
- A.FP16 半精度占 2 字节
- B.Key 和 Value 各一份← 正确答案
- C.多头注意力有两组权重
- D.缓存池预留双倍预算
答案:B。公式里的两个“2“含义不同:第一个 2 是 Key 和 Value 两份缓存,最后一个 2 才是 FP16 每个元素占 2 字节。B 选项准确描述第一个 2。这就像保鲜盒要分”荤素”两层放,同一道菜的两个半成品部位都要占空间,但每个位置的具体大小是另一回事。
Q4. 关于连续批处理和静态批处理,以下说法正确的有?
- A.连续批处理在迭代级调度序列← 正确答案
- B.静态批处理等最长序列完成再整批释放← 正确答案
- C.序列长度差异大时连续批处理利用率更高← 正确答案
- D.连续批处理能彻底消除全部排队延迟
答案:ABC。连续批处理的核心就是迭代级调度(A 对),静态批处理必须等最长序列完成才释放整批(B 对),两者在序列长短差异大时利用率差距显著、连续批处理明显占优(C 对)。D 错在“彻底消除”过于绝对——连续批处理消除的是批次内的气泡,队列排队等待依然存在。
Q5. 推理服务中请求队列的首要作用是什么?
- A.提高单条请求执行速度
- B.承接突发流量解耦到达与处理← 正确答案
- C.减少模型权重的显存占用
- D.替代动态批处理的等待窗口
答案:B。请求队列的核心价值是缓冲:让不稳定的到达流量与稳定的批处理节奏解耦。B 准确。A 中队列反而可能增加等待;C 与显存无关;D 中队列和窗口是配合关系,队列为组批提供“货源”,窗口是触发条件,不能互相替代。
Q6. 自适应批大小调整常用的输入信号包括哪些?
- A.当前队列水位与目标水位← 正确答案
- B.延迟与 SLA 目标的距离← 正确答案
- C.KV 缓存剩余显存量← 正确答案
- D.模型训练时的参数量
答案:ABC。自适应批大小依据系统实时状态做决策:队列水位决定“货多不多”,延迟距 SLA 的距离决定“客人急不急”,剩余显存决定“锅还能不能更大”。D 是模型训练时的静态属性,与运行时调度无关。
Q7. 压测一个新模型服务时,正确寻找最优批大小的流程是?
- A.直接设置为显存允许的最大批
- B.逐步增大批大小找吞吐延迟交叉点← 正确答案
- C.根据模型参数量推导固定公式
- D.先设窗口为无限大再测延迟
答案:B。最优批大小必须在真实压测中寻找:逐步增大批大小,观察吞吐上升曲线与 P99 延迟曲线,在“吞吐拐点”和“SLA 边界”之间取交集。A 忽视了延迟约束,C 中参数量不能直接推导出最优批,D 设无限窗口会掩盖窗口超时触发带来的真实排队行为。
Q8. 生产环境显存预算中,不应包含以下哪一项?
- A.模型权重参数本体
- B.前向激活值中间结果
- C.全部请求的历史输入文本← 正确答案
- D.KV 缓存与显存预留余量
答案:C。显存预算四大项是:模型权重、激活值峰值、KV Cache、预留余量。C 中“全部请求的历史输入文本”并不常驻显存——输入 token 在计算完成后只保留在 KV Cache 中,原始文本由调用方保存。这就像冰柜只存备料和半成品菜,不存客人已经吃完的菜单。
Q9. 以下哪些是提升批量推理吞吐的合法手段?
- A.采用连续批处理减少气泡← 正确答案
- B.动态调整批大小适配流量← 正确答案
- C.无限增大队列长度防止丢请求
- D.用分页注意力管理 KV 缓存← 正确答案
答案:ABD。连续批处理(A)和分页注意力(D)是经典的吞吐优化手段,动态调整批大小(B)则让系统在不同流量下都保持高效。C 中“无限增大队列”会带来内存耗尽和延迟失控,是典型的隐藏炸弹——队列长度必须有上限并配合背压。
Q10. 为什么批处理能加速推理而不是简单线性叠加?
- A.权重加载与前向计算被多个序列分摊← 正确答案
- B.GPU 频率会随利用率自动提高
- C.模型在批处理时自动降低精度
- D.请求之间共享同一个输出结果
答案:A。批处理加速的核心在于多条请求的 token 在同一个 Transformer 前向中并行计算,权重矩阵只需加载一次、被多个序列共享,显存带宽被摊薄。B 中 GPU 频率与利用率无关,C 中精度由配置决定而非批处理自动触发,D 中每个请求的输出各不相同,不存在共享输出。