在 Python 进程之间共享一个大的(只读)二进制字符串? [复制]

Posted

技术标签:

【中文标题】在 Python 进程之间共享一个大的(只读)二进制字符串? [复制]【英文标题】:Sharing a large (read-only) binary string between Python processes? [duplicate] 【发布时间】:2018-01-01 23:08:47 【问题描述】:

我有一个大型的只读 bytes 对象,我需要在几个不同的 Python (3) 进程中对其进行操作,每个进程“返回”(添加到结果队列)基于它们的结果列表工作。

由于这个对象非常大并且是只读的,我想避免将它复制到每个工作进程的地址空间中。我所做的研究表明,共享内存是解决此问题的正确方法,但我找不到一个很好的资源/示例来说明如何使用 multiprocessing 模块准确地做到这一点。

提前致谢。

【问题讨论】:

你使用的是什么操作系统? Linux (Ubuntu LTS)。理想的解决方案也可以在 Windows 上运行,但如果需要,可以牺牲这一点。 然后只需加载您的数据并从您的主进程的全局命名空间访问它 - 在支持 POSIX/fork 的系统上multiprocessing 只是 fork 当前进程,因此您可以进行写时复制好处。只需确保您不做任何修改该数据的操作,因为此时它将被复制到您的子流程堆栈中。 感谢您的提示。我从其他一些 SO 问题中看到我可以利用 CoW,直到 Python 运行时本身更新与对象关联的任何元数据(即,即使我不修改对象本身)。这是一个实际问题吗? 这取决于数据......虽然我知道有一些场景,但标准 CPython 可能不会倾向于弄乱早期初始化的静态访问字符串/字节结构 -如果您以后需要大量数据并使用范围迭代器,我会避免硬切片。 【参考方案1】:

当给定ctypes 类型时,您可以使用multiprocessing.Array,它类似于ctypes.Array,但用于共享内存。

# No lock needed, as no write will be done.
array = multiprocessing.Array(ctypes.c_char, long_byte_string, lock=False)

例如:

>>> import multiprocessing
>>> import ctypes
>>> array = multiprocessing.Array(ctypes.c_char, b'\x01\x02\xff\xfe', lock=False)
>>> array[0]
b'\x01'
>>> array[2:]
b'\xff\xfe'
>>> array[:]
b'\x01\x02\xff\xfe'
>>> b'\xff' in array
True

【讨论】:

感谢您的回复。您是否碰巧知道array[:] 是访问内部(共享)表示,还是在子进程中实例化返回的bytes @woodruffw 内部表示为multiprocessing.sharedctypes.c_char_Array_4。即使对常规字节对象进行切片也会创建一个新对象(即bytestring[1:] is not bytestring)。我假设它必须创建一个新的字节对象来访问整个字节串,但如果你只是参与其中,它不应该使用太多的内存。但这避免了管道和事物,因为它来自共享内存。 再次感谢。不幸的是,我一次需要整个对象,所以我不能对共享的Array 实例做太多事情,除非我可以在不创建新副本的情况下使用内部表示。 @woodruffw 我认为跨进程共享 Python 对象是不可能的,因为进程具有独立的内存空间。您可以拥有(不同的)仅引用相同内存的小对象(像这样,将其视为代理),但您不能在不同进程中拥有具有相同内存位置的对象。 是的,这就是我意识到的。无论如何,谢谢。

以上是关于在 Python 进程之间共享一个大的(只读)二进制字符串? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 多处理中将 Pool.map 与共享内存数组结合起来

在 C 语言中使用 POSIX 在多个进程(不是线程,仅进程)之间共享二进制信号量

为并行进程提供共享只读资源

Python档案袋( 进程与协程 )

在 Spark 中,是不是可以在两个 executor 之间共享数据?

python multiprocessing - 在进程之间共享类字典,随后从进程写入反映到共享内存