Show HN: Runloom – 适用于Python自由线程的Go风格协程
摘要
Runloom是一个新的Python库,为自由线程Python(3.13t/3.14t)提供了Go风格的栈式协程和任务窃取调度器,使得阻塞代码能够在无GIL的情况下跨核心并发运行。它声称在生成吞吐量和调度性能上可以与Go匹敌或超越。
查看缓存全文
缓存时间: 2026/07/10 15:21
robertsdotpm/runloom
来源:https://github.com/robertsdotpm/runloom
Runloom
面向 Python 的 Go 风格有栈协程。编写 阻塞 代码 — fiber(fn)、普通 recv/send、无需 async/await — 然后在单个进程中跨所有核心运行一百万个协程。手写汇编上下文切换 + C 工作窃取调度器 + 网络轮询,专为 自由线程 Python 3.14t(无 GIL)设计。
import threading, runloom
from urllib.request import urlopen
runloom.monkey.patch()
def crawl(url):
# urlopen() 看起来是阻塞的——但 monkey.patch() 会将协程挂起在 socket 上而非 OS 线程上,
# 因此所有 64 次获取在真实核心上重叠执行。
body = urlopen(url, timeout=10).read()
print(threading.get_native_id(), len(body))
def main():
for _ in range(64):
runloom.fiber(crawl, "http://example.com")
runloom.run(8, main) # 8 个 hub 线程 -> 3.14t 上的真实核心(无 GIL)
Runloom 对比 Go
相同机器(64 核,自由线程 CPython 3.13t),8 个 hub / GOMAXPROCS=8,预热稳态。Go 在此约为 2.1 M 次创建/秒。
| 指标 | runloom | Go | 结论 |
|---|---|---|---|
创建 — 纯 C (c_entry) | 2.29 M/s | 2.10 M/s | 超越 Go |
创建 — Python (runloom.fiber) | 1.35 M/s | 2.10 M/s | 0.65× |
| 上下文切换 | 约 75 ns 让出 · 约 560 ns 通道往返 | 约 50 ns Gosched | 相近 |
| 连接/秒 — 抖动(每个请求新建连接) | 约 75–78 k/s | 约 75–78 k/s | 持平 |
| 请求/秒 — 保持连接回声,Python 处理 | 596 k/s | 603 k/s | 0.99× — 持平(C 处理超越 Go) |
| 内存 — 空挂起协程 | 8.8 KB | 2.7 KB | 3.3×(唯一真正的差距) |
简要总结:在 创建、调度和吞吐量 上,runloom 与 Go 旗鼓相当,并在纯创建上超越 Go — 一个运行在 CPython 上的有栈协程运行时,即使使用 Python 处理也能匹配编译语言(饱和状态下 596 k 对比 603 k req/s;C 处理超越 Go)。唯一剩下的真正的差距是 内存:挂起的协程携带 CPython 求值帧,约为 Go 每协程 RSS 的 3.3 倍。 完整跨运行时数据及冷启动对比曲线:基准测试报告 (https://github.com/robertsdotpm/runloom/blob/main/benchmark/report.html) · 性能摘要 (https://github.com/robertsdotpm/runloom/blob/main/docs/dev/PERF_SUMMARY.md)。
runloom.optimize("throughput") # runloom.fiber -> 最大创建速率 (fiber_fast)
runloom.optimize("memory") # runloom.fiber -> 小尺寸栈(默认)
安装
pip install runloom
import runloom # 调度器 + 通道,以及 monkey/time/context/sync/aio
为 CPython 3.11–3.14 提供 预编译 wheel(无需编译器),支持 Linux (x86_64/aarch64)、macOS (arm64/x86_64)、Windows (AMD64);其他平台需要从源码构建。无运行时依赖。
它是什么
- 手写汇编上下文切换(x86_64 SysV, aarch64)— 约 80 ns/次切换,无系统调用;回退到 Windows Fibers / POSIX
ucontext。 - M:N 工作窃取调度器(3.13t)— 每个 hub 的 Chase-Lev 双端队列,每个 hub 的 MPSC 提交队列,唤醒的协程路由回其原始 hub。
- 每协程
PyThreadState快照 — cframe、数据栈、exc_info、contextvars、递归深度;一百万个让出的协程共享其 hub 线程,无帧链断层。 - 网络轮询 — epoll / kqueue / IOCP / WSAPoll / select;协程透明地挂起在文件描述符就绪上,无丢失唤醒的三态挂起-提交机制。
- Go 风格通道 —
Chan(capacity)、select、for v in ch。 - 停滞隔离与恢复 — 一个意外的阻塞调用仅停滞其 hub,运行时检测并恢复(默认开启,3.13t)。
monkey.patch()使阻塞的 stdlib(socket、time、threading、…)变为协作式,因此现有阻塞代码无需修改即可运行。
已有 async def 代码?runloom.aio 桥接在单线程调度器上运行它(runloom.aio.run(main()) ≈ asyncio.run)— 零重写移植路径,但非多核加速(如需多核,请使用带 run(n>1, main) 的同步 API)。
诚实的局限性
- 多核优势需要自由线程 CPython 3.13t(帧快照本身需要 3.11+)。在带 GIL 的构建中,runloom 仍可运行 — 廉价创建、协程模型、网络轮询 — 但如同 asyncio 一样单核。
- runloom 无法提升 Python 每核速度。 CPython 每核约 80k 纯 Python 操作/秒是一个它无法提高的常数;它允许一个进程以阻塞模型同时在每个核心上达到该速度。调度器本身是 Go 级别的。
- 每个协程内存高于 Go(空纤程约 3.3 倍 — CPython 求值帧;C 处理可以缩小大部分差距)。
- 抢占仅在 Python 字节码边界触发 — 运行在紧密纯 C 调用(如
numpy)内的协程会持有其 hub 直到返回(与 Go + cgo 相同)。 - Linux x86_64 / 3.13t 是主要且经过严格验证的目标(200 万连接测试、模糊测试、清理器、形式化模型);其他后端同步维护但深度测试较少。
平台支持
| 操作系统 / 架构 | 切换 | 网络轮询 | 测试情况 |
|---|---|---|---|
| Linux x86_64 | fcontext-asm | epoll | 是 — 硬件,3.11 / 3.12 / 3.13t / 3.14t(主要) |
| Linux aarch64 | fcontext-asm | epoll | qemu |
| macOS x86_64 / arm64 | fcontext-asm | kqueue | 硬件,3.14t |
| FreeBSD / GhostBSD | fcontext-asm | kqueue | 硬件,3.12 |
| Windows 10/11 / Server 2022 | Fibers | IOCP→WSAPoll→select | 硬件,3.14t |
| Solaris / Android / 其他 BSD | ucontext / asm | select / epoll / kqueue | 审查 |
文档与布局
完整指南在 docs/ (https://github.com/robertsdotpm/runloom/tree/main/docs/): 快速入门 (https://github.com/robertsdotpm/runloom/blob/main/docs/quickstart.md) · Asyncio 桥接 (https://github.com/robertsdotpm/runloom/blob/main/docs/asyncio.md) · 同步 API (https://github.com/robertsdotpm/runloom/blob/main/docs/sync-api.md) · 通道 (https://github.com/robertsdotpm/runloom/blob/main/docs/channels.md) · M:N 并行 (https://github.com/robertsdotpm/runloom/blob/main/docs/parallelism.md) · 食谱 (https://github.com/robertsdotpm/runloom/blob/main/docs/cookbook.md) · API 参考 (https://github.com/robertsdotpm/runloom/blob/main/docs/api-reference.md)
| 目录 | 内容 |
|---|---|
src/runloom_c/ | C 扩展:调度器、通道、网络轮询、汇编后端、M:N hubs、停滞恢复 |
src/runloom/ | Python 层:aio、sync、monkey、time、runtime |
tests/ · examples/ · benchmark/ · docs/ | 测试 · 可运行示例 · 基准测试 + 性能测试工具 · 文档 |
从源码构建(贡献者):在克隆仓库中执行 pip install -e .(需要 C 编译器;scripts/install.sh / scripts\install.bat 会引导安装一个)。要针对自由线程 CPython 修改 runloom,请使用 3.13t 解释器。
相似文章
Show HN:Lucen —— 一个通过注释指令并行化 for 循环的 Python 编译器
Lucen 是一个源到源的 Python 编译器,通过注释指令并行化 for 循环,保证产生位一致的结果,并在无法证明并行安全时安全地回退到顺序执行。
自由线程Python:过去、现在与未来
Thomas Wouters 在 PyCon US 2026 上发表了关于自由线程 Python 的过去、现在与未来的演讲,该 Python 版本移除了全局解释器锁 (GIL),允许并行线程执行。
C语言中的Go风格并发
一篇详细的技术文章,探讨如何在C语言中复制Go的并发模型,使用POSIX线程、互斥锁、条件变量和工作池,作为Solod转译器项目的一部分。
Gossamer:一种具有真实goroutines和无暂停内存的Rust风格语言
Gossamer是一种受Rust启发的新编程语言,具有真实goroutines、基于引用计数和区域的无暂停确定性内存管理,以及配备LLVM编译的字节码虚拟机。它旨在提供富有表现力的语法,无需借用检查器或垃圾回收暂停。
Silk: 开源协作式纤程调度器
Silk 是一个面向 Linux 的开源协作式纤程调度器,具有每 CPU 调度线程、io_uring 集成和拓扑感知的工作窃取功能,专为低开销下的高并发而设计。