市中心的「一口锅」火锅店迎来了晚市高峰。后厨只有一口灶,客人点一份毛肚,大厨开火涮一份毛肚;过了一会儿又来了份虾滑,再熄火焖一份虾滑。灶台火候反复起落,真正旺火的时间不到三分之一,其余都在等待、翻台、备菜。门口排队等位的客人越来越多——味道是好,就是出菜太慢。这家火锅店的困境,正是大模型推理服务器的日常:GPU 像一口火力极猛的灶台,但请求一个接一个地「单锅单炒」,算力大量闲置。聪明的后厨后来推出「拼锅」——把相似订单凑一起下口大锅,又发现不同食材可以同锅同煮、按各自的火候出锅。这两套机制,就是本文要讲的主角:Triton 动态批处理(Dynamic Batching)与序列批处理(Sequence Batching)。

岗位关联

动态批处理与序列批处理是大模型推理服务高吞吐、低延迟的基石,掌握它们等于掌握了 AI 工程化面试的必考点和线上系统的调优钥匙。

目录
  1. 可视化演示
  2. 推理瓶颈:一单一炒的困境
  3. 动态批处理:拼锅机制
  4. 序列批处理:同锅同煮
  5. 参数调优:拼锅规则的拿捏
  6. 性能评估:翻台率与等位的账本
  7. 工程实战:后厨运营手册
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示Triton推理服务器的动态批处理、序列批处理与连续批处理三种机制,通过请求队列、GPU批次和时间窗口动画理解核心原理。

本节配有交互动效(进入视口后自动加载,约 3KB)。

动态批处理:时间窗口收集请求 请求在队列窗口内等待收集 达pref_size或delay超时触发 GPU利用率10%→80% 对客户端透明,自动调整批次。

推理瓶颈:一单一炒的困境

「一口锅」火锅店的晚市高峰,后厨只有一口灶。客人点一份毛肚,大厨开火涮一份;刚熄火,又来了份虾滑,重新点火焖一份。灶台的火候反复起落,真正旺火的时间不到三分之一,其余都在等待、翻台、备菜。门口等位的客人越来越多——味道是好,就是出菜太慢。大模型推理服务器和这间火锅店如出一辙:每路用户请求进来,模型都要一步步生成 token,每次推理只产生一个词,就要完整跑一遍 Transformer 前向计算。请求一个接一个「单锅单炒」,GPU 上数以万计的 CUDA 核心大部分时间都在空转,算力利用率低得可怜。

把一次完整推理拆开看:请求从进入到返回,总延迟等于排队等待、输入预填充(Prefill)、逐词解码(Decode)与传输开销之和。解码阶段尤其特殊——它天生是串行的,每生成一个 token 都依赖之前全部 token 的结果,单个请求无法靠并行加速。只有把多个请求「拼」在一起,才能让 GPU 塞满并行计算。这正是后续所有批处理策略的出发点。

想让灶台旺起来,关键不在加快单道菜的火候,而在改变后厨的作业方式——把多个订单凑在一起下锅。这就是动态批处理的雏形。

Ttotal=Tqueue+Tprefill+Tdecode+Toverhead\displaystyle T_{\text{total}} = T_{\text{queue}} + T_{\text{prefill}} + T_{\text{decode}} + T_{\text{overhead}}
总延迟由四段组成:排队等待、输入预填充、逐词解码和调度开销。解码部分是串行瓶颈,必须靠「拼」请求来摊薄。
  1. 总延迟 \(T_{\text{total}}\)一个请求从发出到收到完整结果的全程耗时,是用户感知的响应时间。
    Ttotal\displaystyle T_{\text{total}}
  2. 排队延迟 \(T_{\text{queue}}\)请求在服务队列中等待被调度的时间,流量越高这个值越大。
    Tqueue\displaystyle T_{\text{queue}}
  3. 预填充耗时 \(T_{\text{prefill}}\)模型首次并行处理整个输入序列、产出第一个输出 token 的耗时。
    Tprefill\displaystyle T_{\text{prefill}}
  4. 解码耗时 \(T_{\text{decode}}\)逐步生成每个输出 token 的时间总和,串行依赖、无法内部并行。
    Tdecode\displaystyle T_{\text{decode}}
  5. 调度开销 \(T_{\text{overhead}}\)网络传输、内存拷贝、显存分配等附加时间,看似微小却不可忽略。
    Toverhead\displaystyle T_{\text{overhead}}

动态批处理:拼锅机制

后厨主管想了个办法:把点同一种锅底的订单攒一攒,凑够三份就一起下口大锅。原本一份菜炒 10 分钟,三份一起炒只要 18 分钟——单份平均时间从 10 分钟降到 6 分钟。这就是「拼锅」:不是每单独炒,而是收集订单、合并、一起处理。Triton Inference Server 的 Dynamic Batcher 正是这位「拼锅主管」,它守在推理服务入口,把短时间内到达的多个独立请求收集进队列,凑够一定数量或等待足够久后,合并成一个 batch 一次性交给 GPU。GPU 的矩阵运算天然适合批量执行:一个 batch 的多个请求在矩阵乘法中组织成更大的矩阵并行计算,算力被充分填满。

动态批处理的核心是两个触发条件:批大小满额(max_batch_size)和排队超时(max_queue_delay)。调度器采用贪心策略,不断扫描队列,在「再等等能凑更大批」和「客人等太久了」之间做取舍。因为 GPU 内部并行单元远多于单请求所需计算量,批处理耗时远小于逐个处理的总和,等效加速比由下式给出。

拼锅后平均出菜时间大幅缩短,但新问题浮现:客人点的菜量不一样。有的只点一份毛肚 7 秒出锅,有的点整套火锅要煮半小时。拼成一锅后,短单得陪着长单一起等,灶台上的浪费仍然存在。下一节厨师的答案是——序列批处理。

S=B×tsingletbatch\displaystyle S = \frac{B \times t_{\text{single}}}{t_{\text{batch}}}
加速比等于「串行逐个处理的总时间」除以「合并后一次计算的时间」。因为 GPU 并行,后者远小于前者,所以 S 大于 1。
  1. 批大小 \(B\)一个批次中合并的请求数量,是拼锅的「锅容量」。
    B\displaystyle B
  2. 单请求耗时 \(t_{\text{single}}\)单独处理一个请求的计算时间,相当于一份菜单独炒的用时。
    tsingle\displaystyle t_{\text{single}}
  3. 串行总耗时 \(B \times t_{\text{single}}\)如果逐个处理这批请求,累计需要的总时间。
    B×tsingle\displaystyle B \times t_{\text{single}}
  4. 批处理耗时 \(t_{\text{batch}}\)合并后一次 GPU 计算消耗的时间,因为并行而显著缩短。
    tbatch\displaystyle t_{\text{batch}}
  5. 加速比 \(S\)批处理相对串行的速度提升倍数,S 越大说明拼锅收益越高。
    S\displaystyle S

序列批处理:同锅同煮

真正的大厨知道,火锅的精髓在于「同锅不同熟」:同一口锅,毛肚七上八下即可,土豆要煮足钟头,虾滑浮起就熟。它们共享同一锅汤底、同一个火源,却各有各的出锅时钟。把这个智慧搬进 GPU,就是序列批处理。动态批处理把所有请求当作同等长度处理,batch 中所有序列必须补齐到最长序列的长度,短序列白白陪着长序列跑完整个计算。序列批处理打破了这一约束:它在 token 粒度进行调度,batch 中每个序列独立推进自己的解码循环,共享同一轮 GPU 前向计算;某条序列提前完成,立即让出位置,新序列随即补入。这就是 Continuous Batching(连续批处理)思想在 Triton 中的体现。

序列批处理还依赖一个关键队友——KV Cache。Transformer 解码时,每生成一个 token 都要计算它与历史所有 token 的注意力。KV Cache 把历史 token 的 Key 和 Value 向量缓存下来,避免每条序列重复计算过往内容。配合序列批处理,每个序列只需计算自己最新 token 的那一步,KV Cache 在显存中各自独立维护。由于不再需要 padding,有效计算利用率接近 100%。

毛肚先熟了先捞出,土豆继续在锅里煮着,新下的虾滑立刻占住空出的位置——同一口锅始终满负荷运转,这正是「同锅同煮、按需出锅」的智慧。

η=∑i=1BLiB×Lmax⁡\displaystyle \eta = \frac{\sum_{i=1}^{B} L_i}{B \times L_{\max}}
「有效率」等于所有序列真实长度总和除以补齐后总量。传统 padding 下短序列被白白拉长,η 明显小于 1;序列批处理让 η 接近于 1。
  1. 第 \(i\) 条序列长度 \(L_i\)batch 中每个请求的 token 数量,对应每桌客人的「菜量」。
    Li\displaystyle L_i
  2. 长度总和 \(\sum_{i=1}^{B} L_i\)所有序列真实长度的加总,是真正有价值的计算量。
    ∑i=1BLi\displaystyle \sum_{i=1}^{B} L_i
  3. 最大长度 \(L_{\max}\)batch 中最长序列的长度,传统 padding 批处理的「总锅时长」由它决定。
    Lmax⁡\displaystyle L_{\max}
  4. 补齐总量 \(B \times L_{\max}\)如果全部对齐到最大长度,GPU 需要完成的总体计算量。
    B×Lmax⁡\displaystyle B \times L_{\max}
  5. 有效率 \(\eta\)真实有效计算占补齐后总量的比例,衡量 padding 浪费的程度。
    η\displaystyle \eta

参数调优:拼锅规则的拿捏

拼锅规则不能拍脑袋定:「最多拼几份」定小了灶台常空,定大了先来的客人等到火锅都凉了;「最多等多久」定短了批总凑不满,定长了客人摔碗走人。后厨主管需要根据翻台率数据反复调试这两条规则。Triton 中对应两个核心参数:max_batch_size 决定单次合并的最大请求数,max_queue_delay_microseconds 决定请求在队列中最多等待多久,两者共同控制批处理的「松紧」。此外还可部署多个 Triton 实例并行开火,instance 数量规划同样影响吞吐与延迟。

参数组合的核心矛盾是「等待」与「利用」的平衡:批越大、等待越久,GPU 利用率越高,但单请求延迟越差;批越小、等待越短,响应更快,但吞吐量上不去。工程上可以用排队论模型预估平均排队时长,并设置 preferred_batch_size(偏好批大小)——当队列中请求数达到偏好值立即触发,兼顾响应速度与批规模。

好的后厨主管不会把拼锅规则写死。午市和晚市的客流曲线不同,周末与工作日也不同——Triton 允许在运行中监测队列深度与批大小,结合流量特征动态调整拼锅规则,让灶台始终烧在「火候正好」的状态。

Tˉwait=Nqueue×TbatchBsize\displaystyle \bar{T}_{\text{wait}} = \frac{N_{\text{queue}} \times T_{\text{batch}}}{B_{\text{size}}}
平均等待时间约等于「队列中攒了几批」乘以「每批耗时」。队列越长、批越小,等待越久;批越大,摊薄到每请求的等待越少。
  1. 队列长度 \(N_{\text{queue}}\)当前等待被处理的请求数量,代表后厨门口排队的客人数。
    Nqueue\displaystyle N_{\text{queue}}
  2. 平均批处理耗时 \(T_{\text{batch}}\)一批请求从开始计算到完成平均用时,相当于一锅菜从下锅到出锅。
    Tbatch\displaystyle T_{\text{batch}}
  3. 批大小 \(B_{\text{size}}\)每批能处理几个请求,即一锅能装几份菜。
    Bsize\displaystyle B_{\text{size}}
  4. 需等待轮数 \(N_{\text{queue}} / B_{\text{size}}\)排在后面的请求大概要等多少轮才能轮到自己。
    NqueueBsize\displaystyle \frac{N_{\text{queue}}}{B_{\text{size}}}
  5. 平均等待时间 \(\bar{T}_{\text{wait}}\)请求从进队到开始被计算的平均时长,是用户感知等待的核心。
    Tˉwait\displaystyle \bar{T}_{\text{wait}}

性能评估:翻台率与等位的账本

拼锅和同锅同煮推行一个月,火锅店该算总账了:翻台率升了多少?客人等位时间有没有变长?食材浪费有没有减少?推理服务同样需要一整套指标来评估批处理策略。核心指标是吞吐量(每秒钟处理的请求数或生成的 token 数)和延迟(P50/P95/P99 分位延迟)。动态批处理与序列批处理主要提升吞吐量,但会引入新的延迟问题:批处理中所有请求同进退,批次里最长的那条序列决定整批完成时刻,这就是尾延迟现象。

尾延迟是最典型的代价:P99 延迟往往远高于平均延迟,因为少数长序列会拖累自己所在批次。Amdahl 定律揭示了并行加速的边界——无论把批规模扩大到多大,加速比都受限于串行部分的比例:调度的固定开销、显存拷贝、网络传输,这些永远无法并行。因此设计推理服务时,要根据业务对延迟的敏感度选择合适的批大小上限,并在多 GPU 上做负载均衡,让请求均匀分布到各实例。

火锅店的账本告诉我们:翻台率的提升有边界,一味加大拼锅规模,等位时长就会飙升。让指标说话——把吞吐、P99 延迟、显存占用和队列深度全部纳入每日看板,像翻台率一样持续监测调整。

Sp=1(1−f)+fB\displaystyle S_p = \frac{1}{(1 - f) + \dfrac{f}{B}}
加速比取决于「可并行部分 f」和「串行部分 1−f」。批大小 B 再大,加速比也逼近 1/(1−f),这就是批处理收益递减的根本原因。
  1. 并行比例 \(f\)总计算量中可以被并行处理的部分,如矩阵乘法、token 级计算。
    f\displaystyle f
  2. 串行比例 \(1-f\)无法并行化的部分,如调度、拷贝、网络传输,始终存在。
    1−f\displaystyle 1 - f
  3. 并行度 \(B\)批大小,代表并行扩展的规模。
    B\displaystyle B
  4. 并行后归一化时间 \((1-f) + f/B\)原始耗时 1 被拆成串行与并行两部分后的总耗时。
    (1−f)+fB\displaystyle (1 - f) + \frac{f}{B}
  5. 加速比 \(S_p\)串行耗时除以并行后耗时,B 趋于无穷时收敛到 \(1/(1-f)\)。
    Sp\displaystyle S_p

工程实战:后厨运营手册

这些经验被写进火锅店的《后厨运营手册》:拼锅规则怎么写进排班表、什么时段用多大的锅、食客投诉如何排查。Triton 的工程配置与排障,正是这样一本手册。在 NVIDIA Triton Inference Server 中,动态批处理通过模型配置文件 config.pbtxt 中的 dynamic_batching 字段启用,核心配置包括 max_batch_size、max_queue_delay_microseconds 和 preferred_batch_size。配置完成后,通过 Triton 的指标接口可以观测每个实例的批次大小分布、队列等待时长、利用率等关键数据。

工程实践中最常见的问题是「饥饿」:某些请求(如特别长的序列)总被新到达的请求插队,等待时间遥遥无期。解决方案是设置合理的 max_queue_delay 上限,保证每个请求在队列中存活时间不超过阈值。另一个问题是显存不足(OOM)——KV Cache 和 batch 矩阵同时占显存,需通过监控显存水位控制批大小上限。场景选型上:在线交互场景更看重低延迟,应调小批大小与排队延时;离线批处理场景追求吞吐,可加大批规模与延时容忍。

运营手册最后一页写着:没有一劳永逸的拼锅规则。像所有优秀后厨一样——观察数据、调整规则、测量结果、再调整。Triton 的批处理优化就是这样一个永续迭代的闭环。

Costper=CGPU×TbusyNreq\displaystyle \text{Cost}_{\text{per}} = \frac{C_{\text{GPU}} \times T_{\text{busy}}}{N_{\text{req}}}
单请求成本等于 GPU 单位时间成本乘以繁忙时间,再除以完成的请求数。批处理让同样的 GPU 时间服务更多请求,单位成本随之下降。
  1. GPU 单位时间成本 \(C_{\text{GPU}}\)按小时计费的 GPU 租用成本或电力折旧,是后厨的「灶台租金」。
    CGPU\displaystyle C_{\text{GPU}}
  2. 繁忙时间 \(T_{\text{busy}}\)处理一批请求的总占用时长,对应灶台开火的时间。
    Tbusy\displaystyle T_{\text{busy}}
  3. 总成本 \(C_{\text{GPU}} \times T_{\text{busy}}\)这段时间内产生的全部费用。
    CGPU×Tbusy\displaystyle C_{\text{GPU}} \times T_{\text{busy}}
  4. 请求数量 \(N_{\text{req}}\)同一段时间内完成的请求总数,拼锅越多这个数越大。
    Nreq\displaystyle N_{\text{req}}
  5. 单请求成本 \(\text{Cost}_{\text{per}}\)平均每个请求分摊的费用,批处理的核心经济收益。
    Costper\displaystyle \text{Cost}_{\text{per}}

AI 应用场景

企业级大模型问答服务

阶段:模型部署与推理加速

解决的问题:企业客服机器人面临高并发提问,单请求串行推理导致 GPU 利用率不足 20%,高峰期大量请求排队超时。动态批处理在入口聚合请求,配合序列批处理让不同长度的对话序列共享计算,吞吐量提升数倍。

具体案例:某电商客服系统的 LLM 推理服务峰值达 5000 QPS,引入 Triton Dynamic Batcher 后将 max_batch_size 设为 8、max_queue_delay 设为 50ms,P95 延迟从 6 秒降至 2 秒,GPU 利用率从 22% 升至 67%。

多租户大模型 API 平台

阶段:推理服务编排与资源调度

解决的问题:多个业务线共享同一套推理集群,请求长度差异极大——有的问「你好」两个字,有的上传整篇文档。传统 padding 批处理让短请求陪跑,算力浪费严重。序列批处理配合 KV Cache 让各租户序列独立推进,互不拖累。

具体案例:某 SaaS 公司的大模型 API 平台接入 12 个业务线后,通过 Triton 序列批处理 + 动态批处理组合,集群平均利用率从 35% 提升至 70%,同时通过监控各租户 P99 延迟动态调整实例数量。

Python 演示

python97 行
"""Triton 动态批处理与序列批处理模拟器"""import randomfrom collections import deque  class Request:    """模拟一个推理请求"""     def __init__(self, rid, length, arrive_time):        self.rid = rid        self.length = length          # 序列长度(token 数)        self.arrive_time = arrive_time        self.finish_time = None     def latency(self):        return self.finish_time - self.arrive_time  class Batcher:    """动态批处理器:攒满 max_batch_size 或超过 max_delay 触发"""     def __init__(self, max_batch_size, max_delay, seq_mode=True):        self.max_batch_size = max_batch_size        self.max_delay = max_delay        self.seq_mode = seq_mode        self.queue = deque()          # 等待拼锅的请求        self.active = []              # 正在计算的批次        self.finished = []        self.clock = 0.0        self.remain = 0.0             # 朴素批处理剩余时间     def submit(self, req):        self.queue.append(req)     def tick(self, dt):        self.clock += dt        # 序列批处理:每个请求独立推进,短序列先出锅        if self.seq_mode:            for r in self.active:                r.length -= dt * 10                if r.length <= 0:                    r.finish_time = self.clock                    self.finished.append(r)            self.active = [r for r in self.active if r.length > 0]        else:            # 朴素批处理:以最长序列为准,整体推进            if self.active:                self.remain -= dt                if self.remain <= 0:                    for r in self.active:                        r.finish_time = self.clock                        self.finished.append(r)                    self.active = []        # 尝试凑批:从队列取出最多 max_batch_size 个        if not self.active:            batch = []            while self.queue and len(batch) < self.max_batch_size:                batch.append(self.queue.popleft())            if not batch:                return            waited = max(self.clock - r.arrive_time for r in batch)            if len(batch) >= self.max_batch_size or waited >= self.max_delay:                self.active = batch                if self.seq_mode:                    for r in self.active:                        r.length = max(r.length, 1)                else:                    self.remain = max(r.length for r in self.active) / 10            else:                # 没凑满也没超时,放回队列等待                for r in batch:                    self.queue.append(r)  def run_sim(batch_size, delay, seq_mode, duration=40.0):    b = Batcher(batch_size, delay, seq_mode)    next_t = 0.0    rid = 0    dt = 0.05    random.seed(42)    while b.clock < duration:        if b.clock >= next_t:            b.submit(Request(rid, random.randint(5, 50), b.clock))            rid += 1            next_t = b.clock + random.expovariate(1 / 1.5)        b.tick(dt)    if b.finished:        lat = [r.latency() for r in b.finished]        return len(b.finished), sum(lat) / len(lat)    return 0, 0  if __name__ == "__main__":    print("=== 批处理模拟结果 ===")    print("动态批 batch=4 delay=3.0 朴素模式 =>", run_sim(4, 3.0, False))    print("动态批 batch=4 delay=3.0 序列模式 =>", run_sim(4, 3.0, True))    print("动态批 batch=2 delay=1.0 序列模式 =>", run_sim(2, 1.0, True))
目的:用离散事件模拟对比「朴素批处理」与「序列批处理」在相同请求流量下的吞吐量和平均延迟,直观展示序列批处理的优势。
  1. self.queue = deque()请求到达先进入队咧等待凑批,对应火锅店的等位区。
  2. def tick(self, dt):模拟时钟前进,每步推进所有请求的状态,是调度的核心循环。
  3. r.length -= dt * 10序列批处理中每个请求独立消耗自己的 token 余量,短序列提前完成并退出。
  4. if len(batch) >= self.max_batch_size or waited >= self.max_delay:批处理的触发条件:满额或超时,对应「拼锅」的两个规则。
  5. self.remain = max(r.length for r in self.active) / 10朴素批处理以最长序列为准整体推进,短序列被迫陪跑。
  6. next_t = b.clock + random.expovariate(1 / 1.5)用指数分布模拟随机的请求到达间隔,贴近真实流量。

常见误区

误区把 max_batch_size 调到最大值,GPU 利用率最高、吞吐量最大、性能一定最好。

正解批大小增大意味着单个请求要等更多请求一起处理,排队延迟急剧上升;显存占用随批线性增长,超大 batch 极易触发 OOM。火锅店把锅换到无限大,先来的客人会等到怀疑人生。

为何常见:只看到 GPU 并行计算的收益,忽略了排队等待和显存约束这两个「免费午餐」的账单。

误区认为两者是竞争方案,部署时只能启用其中一个。

正解二者在不同层面互补——动态批处理管入口层的请求聚合(拼锅),序列批处理管计算层的 token 级调度(同锅同煮),可以同时启用形成组合拳。

为何常见:把两个概念都归入「批处理」一个篮子,误以为它们是替代关系。

误区排队延时越小请求响应越快,所以应该把 max_queue_delay 调到很小。

正解延时太小时批常常凑不满,批处理退化为单请求串行,GPU 算力浪费,吞吐量暴跌。真正要做的是根据流量特征找到「等待与利用」的平衡点。

为何常见:只从单个请求视角看延迟,忽略了整体吞吐量才是推理服务的核心指标。

误区KV Cache 只是加速技巧,不占额外显存,随便用。

正解KV Cache 显存占用与序列长度、层数、头数成正比,大模型下动辄数 GB。序列批处理中每个序列独立维护 KV,显存需求会随并发序列数线性增长,必须纳入容量规划。

为何常见:KV Cache 看不见摸不着,容易被当成「不需要付出代价」的优化手段。

误区上线时把批处理参数调好,之后就不用再管了。

正解流量模式随时间变化,早晚高峰、业务活动都可能改变请求到达率与长度分布。需要基于监控数据(批大小分布、队列深度、P99 延迟)持续迭代参数配置。

为何常见:静态思维,认为最优解固定不变;忽略了推理服务的动态性。

面试题

Q1. 动态批处理的核心思想是什么?

单选题 · easy

  • A.把请求序列拆分成小块并行计算
  • B.将多个独立请求合并成批量处理← 正确答案
  • C.增加GPU数量来并行处理多请求
  • D.用CPU替代GPU承担部分计算

答案:B。动态批处理的核心是把多个独立请求合并成一个 batch 交给 GPU 计算,对应火锅店的「拼锅」。A 是序列内部的切分,C 是横向扩展,D 是异构计算,都与动态批处理的本意不符。

Q2. 序列批处理与传统批处理的主要区别是什么?

单选题 · easy

  • A.使用更大的GPU显存容量
  • B.序列长度无需补齐到相同← 正确答案
  • C.每次只处理一个用户序列
  • D.只支持固定长度的输入序列

答案:B。传统批处理要求所有序列 padding 到相同长度,短序列陪跑;序列批处理允许不同长度序列在 token 级共享计算、各自独立完成,正是「同锅同煮」的体现。

Q3. max_queue_delay 设置过大可能导致哪些问题?

多选题 · mid

  • A.请求排队等待时间变长← 正确答案
  • B.整体请求延迟随之上升← 正确答案
  • C.系统吞吐量必然下降
  • D.批处理收益必然减小

答案:AB。排队延时过大会让请求在队列中等待很久,延迟上升;但吞吐量可能因为批次更满而提升,批处理收益也可能增大,所以 C、D 不一定成立。

Q4. KV Cache 在序列批处理中的作用是什么?

单选题 · mid

  • A.缓存训练好的模型参数数据
  • B.存储已生成token的键值状态← 正确答案
  • C.替代主存承载模型权重
  • D.保存输入数据的副本信息

答案:B。KV Cache 缓存的是已生成 token 的 Key/Value 向量,避免每个新 token 重新计算历史注意力,是序列批处理能做到「各序列独立推进」的关键支撑。

Q5. 动态批处理中的「饥饿问题」指的是什么?

单选题 · easy

  • A.请求等待过久还未被处理← 正确答案
  • B.GPU显存容量不足导致报错
  • C.请求队列溢出导致请求丢失
  • D.模型加载失败无法对外服务

答案:A。饥饿指某些请求(如长序列)总被新请求插队,等待时间无限拉长。解决思路是设置 max_queue_delay 上限,保证每个请求的排队时间有界。

Q6. 下列哪些是批处理引入的代价?

多选题 · mid

  • A.增加单请求的排队延迟时间← 正确答案
  • B.增加GPU显存的使用量← 正确答案
  • C.降低系统的总吞吐能力
  • D.加剧调度器的实现复杂度← 正确答案

答案:ABD。批处理的核心收益是提升吞吐量,所以 C 错误。排队延迟、显存占用和调度复杂度都是真实代价——拼锅要等位、锅要更大、后厨调度更难。

Q7. 序列批处理中,当某条序列提前完成解码时会发生什么?

单选题 · hard

  • A.整个batch必须重新从头计算
  • B.该序列让出位置可被新序列填补← 正确答案
  • C.该序列的结果将被直接丢弃
  • D.其他序列全部停止等待其完成

答案:B。序列批处理中每条序列独立完成,短序列「出锅」后空出的位置立刻补入新序列,batch 不中断、不重算。这正是 Continuous Batching 的核心优势。

Q8. Triton 配置中 max_batch_size 设置过小会导致什么?

单选题 · mid

  • A.单请求延迟反而会显著降低
  • B.GPU利用率不足、吞吐量受限← 正确答案
  • C.请求队列持续溢出、请求丢失
  • D.模型推理精度出现明显下降

答案:B。批大小过小时每批处理的请求少,GPU 并行度不足,吞吐量受限。单请求延迟不见得显著降低,队列溢出更多与队列容量相关,推理精度与批大小无关。

Q9. 关于动态批处理与序列批处理的组合使用,正确的是?

多选题 · hard

  • A.动态批处理负责入口层的请求聚合← 正确答案
  • B.序列批处理负责计算层的token调度← 正确答案
  • C.两者必须二选一不能组合使用
  • D.组合使用可兼顾吞吐与显存效率← 正确答案

答案:ABD。两者分层互补:动态批处理在入口把请求拼成批次,序列批处理在计算层让批次内不同长度序列并行推进。组合使用能同时提升吞吐与显存利用效率。

Q10. 批处理场景中尾延迟(tail latency)主要因为什么产生?

单选题 · extreme

  • A.网络传输时延的随机波动
  • B.batch中最长序列拖慢整体完成← 正确答案
  • C.GPU主频随温度动态下降
  • D.请求数据包在网络中丢失

答案:B。批处理中所有请求共享一个完成时钟,最长的序列决定整批的完成时间,导致少数慢请求把 P99 延迟拉高。用 Amdahl 定律看,串行部分(调度等)也会放大尾延迟,但直接原因仍是长序列拖累整批。