如何用 Polars scan_ipc 惰性读取共享内存中的 Arrow IPC?
数据小陈
结论
报错的原因是 pa.py_buffer(shm.buf) 返回 PyArrow Buffer,而它没有 read() 方法。scan_ipc 接受文件路径或带 read() 方法的字节流对象。可以用 pa.BufferReader 包装这个 buffer,再传给 scan_ipc。Polars 文档也将 IO[bytes] 列为 scan_ipc 的有效输入类型。Polars scan_ipc API
修改示例
existing_ = SharedMemory(shm.name, create=False)
buf_ = pa.py_buffer(existing_.buf)
reader = pa.BufferReader(buf_)
try:
lf = pl.scan_ipc(reader)
result = lf.collect()
print(result)
finally:
existing_.close()
shm.unlink()
pa.BufferReader 提供 read() 方法,符合接口要求。原代码创建 LazyFrame 后就关闭共享内存并释放 buffer,但惰性查询要等到 collect() 才会执行。因此,共享内存和 reader 至少要保持有效到收集完成。示例在关闭资源前调用了 collect()。
关于是否零拷贝
这种写法解决了输入对象没有 read() 方法的问题,但不能据此确定整个 scan_ipc 流程都是零拷贝。若要确认内存复制行为或生命周期语义,需要针对实际使用的 Polars 版本进行验证。问题中的环境是 polars[pyarrow]==1.38.1。如果该版本不接受 pa.BufferReader,可以先将 buffer 复制到 io.BytesIO 再扫描,但这会多复制一份数据:
import io
reader = io.BytesIO(bytes(buf_))
lf = pl.scan_ipc(reader)
result = lf.collect()
这条回退路径的复制成本会随 IPC 数据大小增加。如果数据必须留在共享内存中且不能复制,还需进一步确认该版本对 PyArrow reader 的支持情况和实际读取行为。
备注:内容仅供参考。
