0.8MB 跑通 Qwen|第 14-1 篇:大模型推理的连续批处理——iteration-level 调度思想

简介: 本系列《0.8MB跑通Qwen》聚焦ARM端零依赖纯C推理引擎,适配Qwen3-VL多模态模型,在RK3588上实测落地。本文详解iteration-level连续批处理:动态聚合多请求的decode步,单次前向服务多人,兼顾并发与确定性。(239字)

系列:《0.8MB 跑通 Qwen:从零实现 ARM 零依赖纯 C 推理引擎》(30 天 × 90 篇) | 适配模型:Qwen3-VL-8B-Instruct(千问3_VL_8B_Instruct)· Qwen3-VL-2B-Instruct · Qwen3-30B-A3B | 测试设备:RK3588(4×Cortex-A76 + 4×Cortex-A55,aarch64)

系列总纲:《0.8MB 跑通 Qwen》30 天 90 篇 · 总纲(阿里云社区)

上一篇:13-3《回退与收益边界:哪些场景 spec 才划算》 | 下一篇:14-2《单 SSE 流与串行队列:引擎的"单机守则"》

真机实测通过:本文实验已在 RK3588 板端实测完成(2026-09;方法学与原始记录见仓库 docs 与《实验脚本》目录)

一句话导读:连续批处理:真实服务是一堆请求同时进来,naive 排队串行会让第 8 个人等前面 7 个全部生成完——本篇讲推理引擎 iteration-level 按步合批的调度思想,把多个请求的 decode 步合并成一次前向。

关键词:手搓 Qwen 推理引擎、千问大模型推理、连续批处理、iteration-level、并发请求、Qwen3-VL、零依赖纯 C

导语:真实服务里请求是一批批同时来的,谁先谁后?naive 串行会让排在后面的人一直干等。本篇讲推理引擎的 iteration-level 调度思想:每一轮把想要下一步的请求凑成一个动态集合,共用一次权重读取,让「读一遍权重」同时服务多个人。

前 13 天都在优化"一个请求"。可真实服务是一堆请求同时进来:8 个用户各聊各的,谁先谁后?naive 做法是排队串行——第 8 个人要等前面 7 个全部生成完。Day 14 的三篇讲引擎的批处理:把多个请求的 decode 步合并成一次前向,让"读一遍权重"同时服务多个人。

1. 知识点:为什么 decode 可以"合批",而 naive 串行是浪费

decode 每步都在做同一件事:读一遍全部权重,给"当前 token"算下一步。第 13-1 说这是带宽瓶颈——但瓶颈恰恰意味着可以共享:

  • 8 个请求各自 decode:8 次前向 = 8 遍权重读取;
  • 把这 8 个请求的"当前步"拼成一个 mini-batch 做一次前向:1 遍权重读取,同时算出 8 个下一步。

只要 batch 内各请求的序列长度对齐(KV 各自独立、按请求索引),就能合并。这就是 iteration-level(按"步"而非按"请求")调度的核心:每一轮迭代,把所有想要下一步的请求凑齐,统一走一次前向。

两个关键工程点:

  1. 请求可以中途加入/离开:有人 3 轮就结束、有人要 30 轮——batch 不是固定 8 人小组,而是每轮动态集合(这区别于静态"一次处理一组请求"的 naive batching);
  2. 只在前向处合流:每个请求的 token 采样、SSE 流式输出仍是独立的——合批的是"算",不是"状态"。

2. 对应代码:引擎线程 + 每请求 worker 线程

线程模型写在 vllm_batch.c 文件头注释里(第 1–14 行),是全文最好的一张图:

/* Engine thread: the only caller of st_qwen_model_forward_batch. It polls
 * the node table for want_step nodes, runs ONE forward for the whole set
 * (weights read once per step), then bumps each node's done_epoch.
 *
 * Worker thread (per HTTP request): acquires a node (inference state),
 * prefills under the engine mutex, then per step: sample -> submit token ->
 * wait for done_epoch -> stream the decoded chunk. Requests join/leave the
 * batch freely; finished requests free their state back to the pool. */

两句话拆开:

  • 引擎线程(唯一调 st_qwen_model_forward_batch 的线程,第 218 行):轮询"哪些请求想要下一步"(want_step),凑成一个集合,跑一次前向(权重只读一遍),然后统一"发工资"(bump done_epoch)——每个等待的 worker 线程据此醒来继续;
  • 每请求一个 worker 线程:在引擎 mutex 下做 prefill,然后进入循环:采样自己的下一步 token → 提交进 batch → 等引擎线程的那次前向跑完(等 done_epoch)→ 把自己的 chunk 流式发给客户端。

这就是"批处理与 HTTP 协作"的答案(14-2 的承接):HTTP worker 只负责自己的请求,引擎线程独占推理前向,二者通过 want_step/done_epoch 握手,请求随时 join/leave(第 13 行原话),VB_MAX_BATCH = 32(第 29 行)封顶。

开关:--batch-max N(main.c 第 4935 行,默认 0=关)。引擎一次 decode 步现在要"喂多个 token"——对应的内核是 st_qwen_model_forward_batch,它在单 token 前向之外存在(第 9829 行起有批量 GQA/归一化 worker 的结构)。

3. 改动后果:8 个并发请求,批量 vs 串行(板端实测)

口径:RK3588 / Qwen3-VL-2B / 2026-09 / serve 贪婪 / --batch-max 8。8 个短问答请求(内容互不相同),先串行发(队列深度 1,batch 不生效),再8 线程同时发(batch 生效),同一服务进程、同一批 prompt。

模式 8 请求总耗时 备注
串行(--batch-max 8 服务,队列深度 1) 12.95 s batch 空转:每请求独立 decode,权重读 8 遍
8 并发(--batch-max 8) 20.93 s 引擎线程按步合批,但这批短问答反而更慢(见判读 2)
对照:8 并发(无 batch 服务) 10.48 s(≈同服务串行 11.35 s) 推理状态锁上排队:并发≈串行

判读:

  1. 输出全部逐字节一致(Blue / Tokyo / tea / Green / Paris / coffee / Purple / Berlin 各模式相同)——批量合批没有改变结果(14-3 讲 near-tie 边界);
  2. 这批短问答开 batch 反而更慢(20.93s vs 12.95s,+62%):请求各只有 2–6 个 token,合批的"权重只读一遍"红利没机会累积,反而让每轮都迁就批内最慢者(8 个请求同步进退、约 20s 一起收尾)。batch 的收益条件是 decode 步数足够多——仓库文档 优化配置与边界说明.md §3.6 的 1.7×(8B 长对话)与本节 2B 短问答的"+62%"都是真的,差别在场景;短问答要量过再开;
  3. 引擎日志的 batch_active(vllm_admin.c 第 389 行,批内请求数)在并发期间 >1——/admin/api/status 可抓活证据。

测量纪律:同批 8 个 chat 问答,串行基线在不同进程间测得 11.35–12.95 s(±~7% 抖动,Day 7 的老朋友);本文主对照 12.95 vs 20.93 是同服务进程内先后测得,结论方向不受抖动影响。

4. 学员调试任务

  • A 档(板端动手):复测第 3 节:--batch-max 8 起服务,用并发客户端发 8 个请求,再串行发同一批,记录两组总耗时与各自的输出;顺手 curl /admin/api/status 看并发期间的 batch_active。
  • B 档(纯读源码):读 vllm_batch.c 头注释(第 1–14 行)与引擎线程轮询(第 218 行附近),回答:① 为什么"权重只读一遍"在 decode 场景是收益而非负担?② 请求中途结束,引擎线程怎么知道这一轮不用等它?③ VB_MAX_BATCH=32 超了会怎样(提示:VB_SLOT_WAIT_MS 120s 的等待)?

预期输出:你能画出"引擎线程 ↔ N 个 worker 线程"的握手图(want_step → 一次 forward → done_epoch),并解释 batch 为什么是"动态集合"而非"固定小组"。

收尾

  • 本篇源码点名:vllm_batch.c(线程模型注释 1–14、引擎线程 218、VB_MAX_BATCH 29)、main.c(--batch-max 4935)、vllm_admin.c(batch_active 389)、vllm_safetensors.c(批量前向 9829+)。
  • 开源仓库:Kestrel-LLM (Gitee)(AGPL-3.0-or-later 或商业许可,二选一)
  • 下篇预告:批处理线程有了,可每个请求的 HTTP 流还是独立的——14-2 讲 serve 的"单机守则":为什么引擎坚持单 SSE 流 + 串行队列,批处理线程和 HTTP worker 并发乱配会发生什么。
相关文章
|
12天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
7950 15
|
11天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
1753 4
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
11天前
|
人工智能 并行计算 PyTorch
秋叶 ComfyUI 2026 整合包 v3.2 完整部署教程:Python 3.13 + Torch 2.13 全栈升级
秋叶aaaki ComfyUI 2026年8月整合包v3.2正式发布!全面升级Python 3.13.11、PyTorch 2.13.0+cu130及ComfyUI v0.30.2,原生支持MiniMax H3、Wan 2.2、Qwen-Image-2.1等2026主流音视频/图像模型,解压即用,无需环境配置。
1800 12
|
9天前
|
人工智能 编解码 并行计算
MiniMax-H3 一键整合包技术文档:8G 显存运行 AI 漫剧制作 —— 角色替换 / 动作迁移 / 文图生视频部署与调参指南
MiniMax H3 是 MiniMax 开源的全模态视频生成模型,支持文/图/音/视多条件输入,输出最高2K、15秒带双声道音频视频。本文档详述其Int8量化版在8GB显存下的本地一键部署、三段式工作流(EDIT/REPLACE/CONTINUE)、参数调优及常见问题排查。(239字)
|
25天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3800 10
|
19天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
2029 1

热门文章

最新文章