读 tp_worker.py:scheduler 与执行壳之间的 worker 外观#
这章解决什么问题#
前面的运行时架构已经在:
里解释了 worker 壳的职责边界,而代码导读又已经分别补了:
forward_batch_info.pymodel_runner.pymodel_loader
但如果你真的顺着源码往执行层里走,仍然会遇到一个具体问题:
- scheduler 到底是怎样通过一个更稳定的 worker 外观去驱动
ModelRunner,而不是直接把所有控制和执行细节都压到model_runner.py上?
这条链最关键的文件其实是:
python/sglang/srt/managers/tp_worker.py
这章的目标,就是把这棵 worker façade 树正式收成一章。
为什么这棵树值得单独成章#
因为 tp_worker.py 并不是简单的“把 ModelRunner 包一层”。它至少承担了三类职责:
- 把配置和 rank 身份翻译成 worker 实例
- 把调度层的
ModelWorkerBatch编译成ForwardBatch - 把一系列控制动作统一转发给
ModelRunner
也就是说,它不仅是执行壳的外观,也是调度层与执行壳之间的正式边界。
优秀技术书在这里应该明确告诉读者:
- 你不是在读一个多余封装
- 而是在读 scheduler 真正依赖的 worker 契约
一张图:TpModelWorker 在执行主线里的真实位置#
这张图解决的理解障碍是:很多读者会默认 Scheduler -> ModelRunner 是直接关系,但源码里其实明确存在一个 worker façade。
flowchart LR
Sch["Scheduler"] --> Batch["ModelWorkerBatch"]
Batch --> TP["TpModelWorker"]
TP --> Fwd["ForwardBatch.init_new(...)"]
Fwd --> MR["ModelRunner.forward() / sample()"]
TP --> Ctrl["weights / LoRA / memory / worker info"]图比纯文字多解释的一点是:TpModelWorker 并不是“执行以后才有的 wrapper”,它从 batch 入口开始就在参与执行链。
第一层:为什么应该先读 BaseTpWorker#
更稳的顺序,不是直接冲进 TpModelWorker.__init__(),而是先看:
BaseTpWorker
因为它已经很清楚地暴露了这棵树的稳定契约:
forward_batch_generation(...)model_runnerget_tokens_per_layer_info()get_memory_pool()- 各种
update_weights_from_* load_lora_adapter(...)
这说明这棵树的核心不是某个具体模型,而是:
- worker 对上层暴露哪些稳定能力
从系统阅读角度看,这非常重要,因为它让你在进入实现前,先知道 scheduler 和控制面到底期待它提供什么。
get_memory_pool()、get_tokens_per_layer_info() 为什么值得特别提#
它们看起来像小 getter,但其实暴露了一个关键边界:
- scheduler 或更上层有时并不需要整个
ModelRunner - 它只需要问 worker:“你有多少 token 容量、你的 memory pool 长什么样?”
这说明 TpModelWorker 不只是 forward façade,也是一层资源能力查询面。
这和前面调度与内存章节天然回扣,因为很多 admission / cache / profile 决策都建立在这些能力事实上。
TpModelWorker.__init__() 真正在固定什么#
这段构造函数最值得抓住的,不是每个字段,而是几个关键步骤:
- 保存 rank / GPU / parallelism 身份
_init_model_config()_init_model_runner()- 必要时初始化 multi-layer eagle runners
- 初始化 tokenizer / processor
- 同步随机种子
- 确定 overlap、spec、memory pool 等运行人格
也就是说,worker 自己也是一个小型人格编译器。
它并不只是拿现成 ModelRunner 来用,而是先把:
- 这个 rank 应该成为怎样的 worker
这件事钉死。
_init_model_runner() 为什么是执行壳的真正挂载点#
这里会真正构造:
ModelRunner(...)
并把:
model_configmem_fraction_static- rank 身份
req_to_token_pooltoken_to_kv_pool_allocatoris_draft_worker
这些全部接进去。
这说明 TpModelWorker 并不是在运行时才找 ModelRunner,而是从初始化阶段就把它作为内核执行壳牢牢挂好。
也正因为这样,前面的 model_runner.py 章节更像“执行壳内部怎么跑”,而这章更像“执行壳怎样被上层真正接入系统”。
forward_batch_generation(...) 为什么是最值得读的主入口#
如果只读一个函数,那一定是:
forward_batch_generation(...)
因为它把 worker 外观的价值写得非常直接:
- 如果给的是
ModelWorkerBatch,先ForwardBatch.init_new(...) - 再调用
self.model_runner.forward(...) - 如果当前在最后一个 PP rank,就决定是否 sample 或只算 logprobs
- 最后把结果包装成
GenerationBatchResult
这说明 worker façade 的真正职责不是做很多计算,而是:
- 把“调度视图”
- 转成“执行视图”
- 再把结果整理成“上层还容易继续处理的返回视图”
这正是一个优秀 façade 应该做的事。
为什么 forward_batch_embedding(...) 也必须一起看#
这能防止你把 worker 理解成“只服务 token generation”。
forward_batch_embedding(...) 会:
- 先构
ForwardBatch - 再
self.model_runner.forward(...) - 再取 embeddings
这说明 worker façade 同样服务于:
- embedding
- classification
- rerank / score
也就是说,它封装的不是某一种业务,而是整个执行壳的“被上层安全调用”的方式。
为什么 TpModelWorker 里会有那么多 weights / LoRA 控制动作#
前面的运行时架构和控制面章节已经提过:
update_weights_from_diskupdate_weights_from_distributedupdate_weights_from_tensorupdate_weights_from_ipcload_lora_adapterunload_lora_adapter
这些动作放回这棵树再看一次,会更清楚它们的共同点:
- 上层不会直接改
ModelRunner - 它总是先通过 worker façade 进入
这说明 TpModelWorker 不只是执行 façade,也是:
- rank-local 控制 façade
从架构设计看,这很健康,因为它避免了上层到处直接碰 ModelRunner 内部细节。
get_worker_info() 为什么很像这棵树的总结#
它一次性把:
- token 容量
- prefill 容量
- 请求上限
- memory pool 大小
- 随机种子
- device
这些东西打包出去。
这说明对上层来说,worker 真正代表的是:
- 一组可执行能力和资源事实
而不只是“这里有个 forward 方法”。
因此 get_worker_info() 很适合被当成阅读这棵树后的一个自检点:如果你能理解它为什么返回这些东西,说明你已经看懂 worker 在系统里的角色了。
为什么这章和 model_runner.py 章节不重复#
它们分别站在不同层:
model_runner.py讲执行壳内部如何汇合模型、KV、backend 和 samplingtp_worker.py讲这个执行壳怎样被包装成上层真正可驱动、可控制、可查询的 worker 单元
也就是说:
- 一个偏壳内
- 一个偏壳外
把两者都讲清楚,读者才真正能理解“为什么 scheduler 从不直接碰模型执行细节”。
这一层最容易出现的误判#
1. 以为 TpModelWorker 只是 rank 容器#
它实际上还是调度视图到执行视图的关键翻译层。
2. 以为 weights / LoRA 控制面会直接改 ModelRunner#
上层通常先经过 worker façade。
3. 以为非生成路径绕过 worker#
forward_batch_embedding(...) 说明并没有。
如果你要顺着源码读这棵 worker façade 树,推荐顺序是什么#
建议按下面顺序:
BaseTpWorkerTpModelWorker.__init__()_init_model_config()/_init_model_runner()forward_batch_generation(...)forward_batch_embedding(...)- 最后再看 weights / LoRA / memory 信息接口
这样读,你先知道 façade 暴露什么,再看它怎样把执行壳挂进来,最后再看控制与查询分支,最不容易被大文件打散。
小结#
这一章真正要补齐的,是代码导读里执行外壳的最后一块:
ModelRunner是执行壳内部中枢TpModelWorker则是 scheduler 和控制面真正依赖的 worker façade
到这里,执行主线在代码导读层就从:
ForwardBatchModelRunnerSampler
继续长到了:
- 上层到底怎样安全而稳定地驱动这套执行壳
这使整条执行链在源码层更完整地闭环。
叶王 © 2013-2026 版权所有。如果本文档对你有所帮助,可以请作者喝饮料。