
Python 程序员跟并发缠斗了快二十年。从 threading 到 asyncio,从 multiprocessing 到 concurrent.futures,每一代方案都在解决上一代的问题,同时又引入新的麻烦。
微软研究院最近开源的 bocpy 带来了一种截然不同的思路:你不再指挥线程和锁,而是声明规则,让运行时自己决定怎么跑。 这个项目是“行为导向并发”(Behavior-Oriented Concurrency,BOC)的 Python 实现。BOC 范式最初是为微软研究院的实验语言 Verona 设计的,2023 年在 OOPSLA 上发表了正式论文。
今天我想重点聊的不是“bocpy 是什么”,而是我们从一个更刁钻的角度拆开看:它到底简化了什么,没有简化什么,以及它真正值得关注的地方在哪里。
先说结论:这是一种声明式并发
跟传统的 threading + lock/queue 写法比,bocpy 最大的变化在于并发控制的范式。
传统写法是命令式并发:你明确指挥谁先拿锁、谁等待、谁通知队列、谁释放锁。代码里一大半精力花在管理同步上,而不是在管理业务逻辑。
bocpy 是声明式并发协调。你只需要写两件事:
from bocpy import Cown, when, wait items = [Cown(i) for i in range(5)] @when(items) def _(items): # 当这五个 Cown 全部可用时,自动执行 total = sum(c.value for c in items) print("Sum:", total) wait()
Cown(concurrent-owned variable)是“同一时间只能被一个行为拥有的数据”,@when 声明的是“当这些数据准备好了,做这件事”。调度、互斥、触发,全部交给运行时。
你表达的是“当条件满足时做这件事”,而不是“先拿锁 A,再拿锁 B,检查条件,改数据,通知队列,释放锁”。这种差异看起来只是语法糖,但本质上是范式迁移。
一个容易被误读的细节:Cown 不是锁
Cown 不是“加了包装的锁”,它是数据所有权的时间切片。
传统锁的思维方式是:数据是共享的,但我用锁把它保护起来,同一时间只有一个线程能访问。锁本身是一个协调工具,跟数据是分离的。
BOC 的思维方式是:数据本身携带所有权信息。当你把一份数据放进 Cown,这份数据在任何时刻只能归一个行为所有。别的行为不是“被锁挡住了”,而是这份数据此刻不属于它。这很像 rust 里的借用机制&mut T,只是 bocpy 的独占访问是运行时的调度器保证。bocpy 的调度器通过两阶段锁定,按 Cown 的 ID 排序后获取,从算法层面保证了死锁不可能发生。
这个区别不只是理论上的。它直接决定了你写代码时的思维方式:从“我要在正确的时间加锁和解锁”,变成了“我要把数据流组织好,让每个行为在正确的时机拥有正确的数据”。
性能:真正并行的前提条件
关于性能,官方基准测试的数据是:在 Python 3.14 上,worker 数量从 1 增加到 8 时,吞吐量实现了约 7.5 倍的加速,接近线性扩展。另有技术文章报告在 14 核 AMD 机器上使用 16×16 矩阵负载,bocpy 的表现“接近完美的线性扩展”,并评论这是 GIL 锁定下的 threading 方法三十年来未能实现的。
但这些数据有一个硬门槛:必须在 Python 3.12 及以上版本才能实现真正的并行。
原因在于子解释器机制。Python 3.12 根据 PEP 684,让每个子解释器拥有自己独立的 GIL。bocpy 把不同的行为调度到不同的子解释器中运行,每个子解释器有自己的锁,互不阻塞。GIL 本身没有被移除,但 bocpy 通过“复制”多个 GIL,让它们各管各的。
在 Python 3.10 和 3.11 上,所有子解释器共享同一个进程级 GIL,行为仍然是串行执行的。官方明确建议:3.10/3.11 只用来看兼容性,不要指望性能。
它真正值得关注的地方
如果只把 bocpy 看作“又一个并发库”,会低估它。
Python 语言峰会的演讲中有一个信号值得注意:CPython 核心团队在 PEP 779 的接受信息中明确表示,“应该开始考虑和提出更高层的并发原语,让用户能够安全有效地使用,而不需要深入理解底层线程机制”。演讲中甚至讨论了是否应该把类似 bocpy 的能力放进标准库的 concurrent 包中。
也就是说:bocpy 可能不只是微软的一个实验项目,它是 Python 并发模型演进的一个候选方向。
而它的范式——声明式并发——恰好契合了 Python 社区对“让并发变得不需要专家知识”的追求。传统 threading + lock 的“舒适接口”被峰会演讲直接批评为“实际上并不好”,因为最终用户仍然需要关心死锁和竞态条件。
当然,bocpy 目前仍然是实验项目,不建议直接上生产。但如果你在做 CPU 密集型的并行计算,或者想提前感受一下 Python 并发编程可能的方向,它值得花一个下午跑一跑。
free-threaded Python 上的“纯粹开销”问题
目前 bocpy 在无 GIL 的 free-threaded Python(3.13t、3.14t 等)上也可以不加修改地运行,数据竞争和死锁的保证依然有效。
但在这种环境下,子解释器和 XIData(跨解释器数据序列化)机制变成了纯粹的开销——因为普通线程在主解释器中本来就能并行执行,子解释器的隔离反而增加了不必要的序列化和通信成本。
项目已经用 Issue #5 跟踪这个问题,计划添加一个直接线程后端:当检测到 free-threaded 解释器时,跳过子解释器、转译器和 XIData 路径,直接用普通线程执行行为。这个计划出现在 Python Language Summit 2026 的演讲中,被定位为“为 CPython 标准库做 PoC 实现”和“PEP 准备”的前置工作。
关键是:这个后端不会改变你的代码。 Cown 和 @when 的公开 API 完全不变,你之前写的 bocpy 程序不需要改一行。简化的是运行时内部路径,不是你的业务逻辑。
代码的写法,可能比你想的要简单得多。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14568/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料