在 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 在多个进程(不是线程,仅进程)之间共享二进制信号量