三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

把首 token 延迟从 820ms 压到 210ms,我只拆了这两层

把首 token 延迟从 820ms 压到 210ms,我只拆了这两层

连续批处理 + 投机解码:我把首 token 延迟拆开算了一遍

系列第 2 篇 · 性能优化

⚠️ 数据性质声明(先看这段,避免误读):本文的「连续批处理 1.2×」「投机解码 0.85×–1.77×」以及第五节「TTFT ~820ms→~210ms」均为本地算法队列仿真(sim_latency.py,参数标注为示意值)与公开经验区间并非在 GPU 上实测。脚本可复现、结论方向稳定,但绝对数字请以你自己的硬件压测为准。本地推理基准已在本系列第 3、4 篇以「本人实测」补上:本机 torch 加载 CUDA 扩展崩溃(GPU 不可用),改用纯 NumPy CPU 推理引擎实跑 Qwen2.5-0.5B/1.5B 延迟(约 15/5 tok/s)与量化损失(int8 94%/int4 82%)。

很多人以为投机解码「一定更快」,但我用排队仿真算了一笔账:草稿接受率 α=0.3 时,加速比只有 0.85×——它反而比朴素自回归更慢。延迟优化不是堆技术,是算账。

上篇我们定了选型,这篇把「为什么你的 LLM 接口时快时慢」拆成两段工程手段,给可量化加速比。


一、先把两个指标分清(别混着优化)

  • TTFT(Time To First Token):从发请求到出第一个字。受预填充/批处理/排队主导。
  • TPOT(Time Per Output Token):之后每个字的间隔。受解码算力/批大小主导。

错配最常见:接口整体慢,你狂优化 TPOT,其实 70% 时间卡在 TTFT 的排队。先测再动刀。


二、连续批处理:把吞吐翻倍的真功夫

传统「静态批处理」要等凑满一批才跑,短请求陪长请求空等,尾部请求直接被丢弃。连续批处理(continuous batching)每个 GPU step 只解在飞请求各 1 个 token,谁结束谁立刻让位。

我用纯算法仿真(token 级队列,不加载模型)跑了 200 个突发请求(到达率 4 QPS,最大批 16,示意硬件单卡):

方案排空 200 请求服务数结果
连续批处理59.1 s200/200零丢弃
静态批处理(凑满才跑)69.2 s192/200丢弃 8 条

仿真结论:本模型下连续批处理快约1.2×,且零丢弃。vLLM 官方称其连续批处理较 HuggingFace Transformers 吞吐提升2–4×(公开数据,含 PagedAttention 等额外优化,非本人实测)。

仿真可复现:脚本sim_latency.pypython sim_latency.py即得上表。参数均标注为示意值,结论方向稳定。


三、投机解码:草稿先猜,主模型验

思路:用小草稿模型先并行猜 D 个 token,主模型一次验证。接受率高就白赚 D−1 个 token。

加速比公式(主模型每步 t、草稿每步 d、接受率 α、草稿数 D):

加速比 = (t / (t + D·d)) × (1 + α·D)

我取示意值(主 40 tok/s、草稿 100 tok/s、D=4)算出的真实仿真表:

草稿接受率 α加速比判定
0.30.85×变慢 ⚠️
0.51.15×变快 ✅
0.71.46×变快 ✅
0.91.77×变快 ✅

四、反直觉:高并发 / 长输出下它反而变慢

  • α 低就亏:草稿猜不中,验证 step 白花时间,净负(见上表 0.85×)。
  • 草稿太贵也亏:草稿模型若与主模型抢显存,会挤小最大批,连续批处理的收益被打掉,再加投机验证的固定 step 开销,端到端可能净负。
  • 长输出才是投机的主场:输出越长,省下的解码步越多;短问答上投机几乎没赚头。

五、真实账(示意区间,非本人实测)

业界常见改造区间(公开经验值,示意):

  • 某接口 TTFT 从~820ms 压到 ~210ms,靠两层:① 开连续批处理消灭排队;② 多轮场景开 prefix cache 复用历史 KV。
  • 这只是示意量级,真实数字取决于你的批大小、序列长度、显存。请在你机器上用上篇 vegeta 压基线后对比。

六、该上 / 不该上 判断清单

上投机解码:输出长(>128 token)、草稿模型便宜、接受率预期高(如代码补全)。别上:短问答、高并发已吃满显存、草稿与主模型同卡争资源。上连续批处理:几乎必上,它是现代推理引擎的默认底座,先确认你的引擎开了。


七、读者交付物

延迟拆解流程图(TTFT = 排队 + 预填充;TPOT = 解码):可截图留存。 ②投机解码适用判断清单(见第六节)。 ③仿真脚本sim_latency.py:改TPOT/draft/α即可算你场景的加速比。


结尾:今天就能动手的 3 条清单

  1. 先拆指标:在接口侧分别打点 TTFT 与 TPOT,确认慢在哪一截再优化。
  2. 确认连续批处理已开:vLLM/SGLang 默认开,自研或老框架要手动确认,否则吞吐腰斩。
  3. 投机解码先算账:用sim_latency.py代入你的 α 估算,<1 就别上。

实测环境与免责:连续批处理 / 投机解码加速比由sim_latency.py在本地算出(纯算法队列仿真,不加载模型权重,参数标的为示意值,方向稳定可复现)。第五节延迟区间为公开经验示意值,非本人实测。硬件示意单卡消费级 GPU。本地真实推理基准已在本系列第 3、4 篇以「本人实测」补上:本机 torch 加载 CUDA 扩展崩溃(GPU 不可用),改用纯 NumPy CPU 推理引擎实跑 Qwen2.5-0.5B/1.5B 延迟(约 15/5 tok/s)与量化损失(int8 94%/int4 82%)。数据基于本人环境,仅供参考,请以你自己的硬件复测。

下篇我们聊:显存不够怎么办?——GPTQ / AWQ / GGUF 量化三件套实测。

← 返回列表