返回资讯中心
外部精选
软件工程
#开发者实时流

Mizu 发布:基于共享内存实现 R 与 Python 零拷贝并行通信

来源标题:Mizu – zero-copy parallel R and Python over shared memory

Mizu 提供基于共享内存的零拷贝通信层,让 Python 和 R 之间的任务往返从约 100 微秒降至 1 微秒以内。其通道和任务池支持列表、字典、numpy 数组和 Arrow 表等结构跨语言共享视图,并保持进程级故障隔离。项目目前处于实验阶段,API 尚不稳定,可通过 pip install pymizu 安装。

Hacker News 最新cscheid2026/11/5 · 5 天前12 分钟阅读

以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。

通过共享内存实现线程级速度的异步与并行 Python。

任务往返时间从通过 socket 的约 100 µs 降至不足 1 µs,因此你可以像使用线程那样对工作进行细粒度划分(参见基准测试)。列表、字典、numpy 数组和 Arrow 表等常见数据结构可以在 Python 和 R 之间以零拷贝视图的形式共享。

在默认的 CPython 构建中,GIL 一次只能在一个核心上运行 CPU 密集型线程,因此 Python 中的计算并行通常意味着多进程。

进程还能隔离故障:某个 worker 崩溃不会连带拖垮宿主进程。

通道和 work-stealing 任务池运行在 POSIX 共享内存(Linux、macOS)或 Win32 文件映射(Windows)之上:无锁的单生产者单消费者环形缓冲区,支持批量发布;等待策略为先自旋后挂起,在热路径上不会进入内核;当对端死亡时会收到操作系统通知。

pymizu 构建于 libmizu 之上,后者是一个用于无锁共享内存 IPC 的 C 库。

mizu 为 R 绑定了同一套核心,因此 Python 和 R 可以互相通信。

生命周期:实验阶段。API 尚未稳定,我们可能会根据反馈做出更改。

pip install pymizu

或从 GitHub 安装开发版本:

pip install git+https://github.com/shikokuchuo/pymizu

需要 Python 3.10 或更高版本,且平台为 64 位。

该扩展会编译随附的 C 核心,因此无需系统库。

若要在 GitHub 安装时请求额外依赖,请使用 pip install "pymizu[numpy] @ git+https://github.com/shikokuchuo/pymizu"。

import pymizu with pymizu.Pool.create(4) as pool: task = pool.submit(pow, 2, 16) print(task.collect(timeout=5))

基准测试

与标准库 concurrent.futures 池的通信开销对比(Apple M4 Pro,来自 benchmarks/mizu-stdlib-bench.py):

对比 ProcessPoolExecutor(任务在独立进程中运行,负载需要 pickle 序列化):

对比 ThreadPoolExecutor(任务共享同一进程,因此 GIL 将 CPU 密集型工作限制在单个核心上):

benchmarks/mizu-bench.py 可单独运行 pymizu 各行。

了解 pymizu 与 Ray、Dask、joblib 以及现代 CPython 的对比。

  • elt = 元素;每个 map 元素的墙钟时间,单位为微秒。

PoolExecutor 将池适配为标准库 concurrent.futures.Executor 接口,因此针对 ProcessPoolExecutor 编写的代码可以直接替换使用。

submit 返回真正的 Future 对象,因此 wait / as_completed / asyncio.wrap_future 均可照常使用:

with pymizu.PoolExecutor.create(4) as ex: futures = [ex.submit(pow, 2, i) for i in range(4)] print([f.result() for f in futures])

并行 map

Pool.map(fn, x) 在池上对 x 映射 fn,并立即返回一个 Map 句柄,正如 Pool.submit() 返回一个任务一样。对句柄调用 collect() 会等待并按顺序返回结果值。

函数和数据只进入共享内存一次。

Worker 在彼此之间划分元素,从共享游标中领取区间。

map 还支持嵌套:被映射的函数可以通过 pymizu.current_pool() 在自己的池上进行 map,且不会死锁。

with pymizu.Pool.create(4) as pool: m = pool.map(abs, range(-5, 5)) print(m.collect())

R 互操作

池的 worker 可以是运行 mizu 包的 R 进程,mizu 是同一核心的 R 绑定。

pymizu.r_launcher() 负责启动它们,pymizu.call() 指定任务。下面这个例子在 R 中汇总内置的 mtcars,再读回 polars:

import polars as pl import pymizu with pymizu.Pool.create(4, launcher=pymizu.r_launcher()) as pool: task = pool.submit( pymizu.call(source="aggregate(mpg ~ cyl, data = mtcars, FUN = mean)") ) print(pl.DataFrame(task.collect()))

numpy 数组传入 R 时成为 numeric 向量,polars、pyarrow 或 pandas 数据框传入时成为 data frame

向量或数据框返回时成为 numpy 数组或 pymizu.Frame

Arrow 数据(pyarrow 表与 record batch reader,或任何 arrow_c_stream 生产者)以同样的方式传递

R 互操作页面给出了完整契约:可移植子集、pymizu.Frame、零拷贝数据框以及 dtype 矩阵。

mizu README 展示了反方向:由 R 宿主通过 mizu_py_launcher() 驱动 Python worker。

文档站点覆盖了整个包:通道及其传递的内容、任务池(批量操作、嵌套任务、concurrent.futures 执行器、监视运行中的池)、并行 map(调度、可复现随机性、模板、预备 map)、R 互操作与 dtype 矩阵、Linux 上的部署,以及 API 参考。

仓库结构与贡献者说明参见 CONTRIBUTING.md。

MIT。

LICENSE.note 包含随附 libmizu 核心的 RngStreams 署名信息。

请注意,本项目发布时附带贡献者行为准则。参与本项目即表示你同意遵守其条款。

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →