读 distributed/parallel_state.py:并行组真正从哪里来#

这章解决什么问题#

代码导读前面已经给了 disaggregation/scheduler.pyEnginemodels/layers/ 的多条阅读路径,但还有一棵对多并行理解极其关键的源码树没有被正式导读:python/sglang/srt/distributed/parallel_state.py 以及它周围的 distributed/ 目录。

如果不把这棵树讲清楚,读者会知道 TP / PP / world group 存在,却不知道它们在源码里究竟从哪里来、谁在维护它们,以及后续通信算子为什么总是反复去 get_tp_group()

为什么这层值得专门成章#

因为对于多并行 runtime 来说,这棵树本身就是“通信现实”的总入口。你后面看到的很多东西都在依赖它:

  • scheduler / tp_worker 初始化
  • communication_op.py
  • graph capture context
  • group-aware all-reduce / all-gather

也就是说,这不是只给分布式专家看的目录,而是整本书运行时边界非常重要的一棵树。

一张图:parallel_state.py 在整本系统里更像“并行地基”#

这张图解决的理解障碍是:很多读者会把 parallel_state.py 当成后台工具,而不是认为它是后面大量执行边界的地基。

flowchart TD
    Dist["distributed/parallel_state.py"] --> Groups["world / tp / pp / moe groups"]
    Groups --> Worker["scheduler / tp_worker"]
    Groups --> Comm["communication_op.py"]
    Groups --> Graph["graph_capture context"]

这张图比纯文字多解释的一点是:后面很多看似分散的执行与通信路径,实际上都在依赖同一棵地基树。

为什么应该先读文件头而不是直接找某个 get_*_group()#

文件开头已经把 workflow 写得很清楚:

  • init_distributed_environment
  • initialize_model_parallel
  • 使用 distributed stuff
  • destroy_model_parallel
  • destroy_distributed_environment

这其实已经给出了最稳的阅读顺序。也就是说,第一次读这棵树时,不应该先去追某个 group getter,而应该先把整个生命周期顺序立起来。

GroupCoordinator 为什么是这棵树的中心对象#

阅读这棵树时,最值得先抓住的不是所有 helper,而是 GroupCoordinator。它解释了:

  • group 是什么
  • local_rankrank_in_group 的区别是什么
  • CPU group / device group 如何同时存在
  • 后续通信操作究竟由谁接管

从系统书角度看,这就是“并行组在程序里的真正对象形状”。

为什么 init_distributed_environment(...)initialize_model_parallel(...) 要配对读#

因为前者更像“把 world 拉起来”,后者更像“把 world 再切成 tp / pp / moe / attn 等更细 group”。如果只读一个,你会很容易误判:

  • 要么以为分布式环境初始化完就够了
  • 要么以为 model parallel group 是凭空长出来的

把它们配对起来,才能真正看见“环境初始化”和“并行语义初始化”是两件不同的事。

graph_capture(...) 为什么值得从这里回扣#

这段代码很有代表性,因为它说明 graph capture 并不是只服务某个 backend,而是会和 tp_grouppp_group 这类 group 对象一起协作。也就是说,graph capture 本身也已经站在 parallel state 之上。

这正是大系统技术书该强调的回扣点:后面的 execution 优化并不是平地起高楼,而是一直踩在 parallel state 这层地基上。

为什么 communication_op.py 更适合在这章里顺手看#

因为它几乎就是 parallel_state.py 的应用侧缩略图:

  • all_reduce
  • all_gather
  • fused 通信路径

这些函数不断用 get_tp_group(),正好能帮助读者确认:group getter 在系统里不是抽象概念,而是后续很多通信路径的直接依赖。

更稳的阅读顺序#

建议这样读:

  1. 文件头 workflow
  2. GroupCoordinator
  3. init_distributed_environment(...)
  4. initialize_model_parallel(...)
  5. get_world_group() / get_tp_group() / get_pp_group()
  6. graph_capture(...)
  7. 最后再顺手看 communication_op.py

这条顺序的核心是:先立生命周期,再立 group 对象,再看谁在消费它们。

这一层最容易出现的误判#

1. 把 parallel_state.py 当成一堆 getter 函数#

实际上它更像整套并行边界的生命周期中心。

2. 以为 group 只是通信时临时拿一下的全局变量#

它们有显式初始化、注册、graph capture 协作和生命周期管理。

3. 以为 graph capture 和 distributed group 是两套独立体系#

源码显示后者是前者的重要前提。

小结#

这一章真正要补齐的,是代码导读里对多并行地基树的正式入口:

  • parallel_state.py 不是工具箱,而是并行世界的状态中枢
  • 它定义了 group 如何初始化、如何暴露、如何被后续执行层消费

到这里,代码导读对分布式这棵树也不再是空白。