Hotdry.

Article

行为导向并发:微软为 Python 设计的下一代并发范式

探索微软研究院提出的行为导向并发(BoC)模型,解析其与 Python 多解释器架构的融合路径及工程实践要点。

2026-05-06systems

当我们在 Python 中谈论并发时,GIL(全局解释器锁)几乎是绕不开的话题。这个设计让 Python 在单进程内只能有一个线程执行字节码,虽然简化了运行时实现,却也让多核 CPU 无法直接提升 Python 程序的性能。随着 Python 3.12 引入单进程多解释器功能,微软研究院正在推进一项更根本的变革 —— 行为导向并发(Behaviour-Oriented Concurrency,简称 BoC),它试图从并发模型层面重新定义 Python 的并行能力。

为什么需要行为导向并发

传统的并发编程范式通常将并行性(parallelism)与协调(coordination)视为两个独立的问题。线程池负责并行执行,而锁、信号量、通道等机制负责协调。这种分离设计虽然灵活,但二者决策紧密耦合:并行粒度的选择直接影响同步成本。actor 模型是这一思路的典型代表 —— 将程序状态分解为可以独立并行执行的 actor,通过消息传递实现协调。然而,actor 模型存在一个核心痛点:原子性地更新多个 actor 极其困难。当一个业务操作需要同时修改多个资源时,传统的两阶段提交或分布式事务方案会带来显著的性能开销和复杂性。

行为导向并发正是为解决这一痛点而生。它的核心思想是将并行与协调统一到一个原语中:行为(behaviour)。一个行为描述了对一组资源(微软称之为 cown,即 capability owner 的缩写)的独占访问需求,运行时保证只有在能够原子性地获取所有指定资源的独占权时,该行为才会被执行。这种设计从根本上消除了数据竞争和死锁的可能性,因为任何时刻最多只有一个行为可以访问同一组资源。

BoC 的核心机制与工程权衡

行为导向并发的运行时模型可以类比为数据库事务,但针对并发场景进行了优化。每个 cown 代表一个可以被独占访问的资源,行为则相当于事务,其执行前提是获得所有声明资源的独占权。运行时维护一个等待队列,根据资源的依赖关系智能调度:当某个行为所需的所有资源都可用时,它被立即调度执行;如果部分资源被其他行为持有,则该行为进入等待状态。这种调度策略天然避免了循环等待,从而杜绝了死锁。

与 actor 模型相比,BoC 的关键优势在于多资源协调的表达能力。在 actor 模型中,如果需要原子性地修改两个 actor 的状态,开发者要么引入额外的协调 actor,要么使用两阶段提交协议,代码复杂度和运行开销都显著增加。而在 BoC 中,只需声明行为需要同时访问这两个 cown,运行时自动处理原子性保证。从微软研究院的基准测试来看,基于 BoC 的实现相比 actor 模型在 Savina 基准套件上表现出相当甚至更优的性能,同时代码更为紧凑。

当然,BoC 也不是没有工程代价。首先是调度开销:运行时需要追踪所有 cown 的状态和等待队列,在高并发场景下这个调度器的复杂度不低。其次是资源粒度设计:如何合理划分 cown 是关键 —— 划分过细会增加协调成本,划分过粗则会降低并行度。这需要开发者在设计阶段对数据访问模式有清晰的预判。

从 PyErlang 到 Python 的 BoC 之路

微软研究院将 BoC 引入 Python 的路径并非一步到位,而是通过一个名为 PyErlang 的中间步骤逐步推进。这反映了 Python 语言自身的特殊性:它诞生于单核时代,运行时设计围绕 GIL 展开,文化上重视灵活性和动态性,而非严格的不可变性或所有权模型。

PyErlang 利用了 Python 3.12 引入的多解释器特性。在该版本中,单个进程可以运行多个 Python 子解释器,每个子解释器拥有独立的 GIL 和私有堆内存,之间通过序列化协议进行数据交换。微软研究院在此基础上增加了跨解释器的共享不可变数据能力,允许通过引用在不同解释器间共享数据,而无需担心某个解释器的垃圾回收器影响其他解释器。这种设计让 Python 获得了类似 Erlang 的进程隔离能力,同时保留了 Python 生态的兼容性。

在 ICFP/SPLASH 2025 的 Erlang 工作坊上,Uppsala 大学的 Tobias Wrigstad 展示了 PyErlang 的核心挑战:在 Python 这种鼓励反射和动态修改的语言中,如何 retro-fit 不可变性约束,以及如何在没有追踪式垃圾回收的情况下处理循环不可变数据。这些技术问题的解决为最终将完整的 BoC 模型引入 Python 奠定了基础。

实践参数与监控要点

对于希望在现有 Python 项目中探索 BoC 思想的开发者,以下参数和监控点值得关注:

在调度层面,建议配置行为超时阈值(通常建议 30 秒至 5 分钟),避免因资源竞争导致的长时间等待。同时监控等待队列长度,如果某类资源的等待行为数量持续超过 CPU 核心数的两倍,说明资源划分可能过细,应考虑合并。在资源管理层面,每个 cown 的访问频率应作为划分依据 —— 高频共同访问的资源应划分为同一 cown 以减少调度开销,而高频独立访问的资源应分属不同 cown 以保持并行度。在错误处理层面,BoC 行为执行失败时应支持自动重试或回滚,需要在运行时配置重试策略(推荐指数退避,最大重试次数 3 至 5 次)。

从生态系统演进来看,BoC 完整进入 Python 可能还需要数年时间,但 PyErlang 代表的中间步骤已经展示了可行性。对于构建高并发 Python 系统的团队,关注这一方向有助于提前布局下一代并发基础设施。

资料来源:微软研究院论文《When Concurrency Matters: Behaviour-Oriented Concurrency》(OOPSLA 2023);ICFP/SPLASH 2025 Erlang 工作坊 PyErlang 主题演讲。

systems