python共享内存mmap_python - IPC在单独的Docker容器中的Python脚本之间共享内存 - 堆栈内存溢出...

时间:2025-05-11 07:18:38

问题

我已经编写了一个神经网络分类器,该分类器可以获取海量图像(每张图像约1-3 GB),将其打补丁,然后分别通过网络传递这些补丁。 培训的进行过程非常缓慢,因此我对其进行了基准测试,发现用大约50秒的时间将补丁从一个图像加载到内存(使用Openslide库 ),而仅需0.5秒的时间就可以将它们通过模型。

但是,我正在使用具有1.5Tb RAM的超级计算机,其中仅使用了约26 Gb。 数据集总计约500Gb。 我的想法是,如果我们可以将整个数据集加载到内存中,它将极大地加快训练速度。 但是我正在与一个研究团队合作,我们正在多个Python脚本之间进行实验。 因此,理想情况下,我想将一个脚本中的整个数据集加载到内存中,并能够在所有脚本中对其进行访问。

更多细节:

我们在单独的Docker容器中(在同一台机器上)运行各个实验,因此必须跨多个容器访问数据集。

图像以.tif格式存储。

我们只需要阅读图像,而无需编写。

我们只需要一次访问数据集的一小部分。

可能的解决方案

我发现了很多关于如何在多个Python脚本之间共享Python对象或内存中的原始数据的文章:

跨脚本共享Python数据

多处理模块中具有SyncManager和BaseManager的服务器进程|

肯定:可以由网络上不同计算机上的进程共享(可以由多个容器共享吗?)

可能的问题:根据文档显示,速度比使用共享内存慢。 如果我们使用客户端/服务器在多个容器之间共享内存,那会比从磁盘读取所有脚本的速度快吗?

可能的问题:根据此答案 , Manager对象在发送对象之前先对其进行腌制,这可能会使速度变慢。

可能的问题: mmap将文件映射到虚拟内存,而不是物理内存 -它创建一个临时文件。

可能的问题:因为我们在同一时间只能使用数据集的一小部分,虚拟内存使整个数据集在磁盘上,我们遇到颠簸问题和程序slogs。

Pyro4 (Python对象的客户端服务器)|

适用于Python的sysv_ipc模块。 这个演示看起来很有希望。

可能的问题:也许只是较低程度地展示了内置的multi-processing模块中可用的功能?

我还在Python中找到了IPC /网络选项列表 。

有些人讨论服务器-客户端设置,有些人讨论序列化/反序列化,这恐怕会比从磁盘读取花费更多的时间。 我找不到任何答案可以解决我的问题,这些答案是否会导致I / O性能的提高。

跨Docker容器共享内存

我们不仅需要在脚本之间共享Python对象/内存; 我们需要在Docker容器之间共享它们。

Docker 文档很好地解释了--ipc标志。 根据文档的运行情况,对我来说有意义的是:

docker run -d --ipc=shareable data-server

docker run -d --ipc=container:data-server data-client

但是,当我在如上所述设置--ipc连接的单独容器中运行客户端和服务器时,它们无法相互通信。 我读过SO问题( 1 , 2 , 3 , 4 )不以单独的Docker容器Python脚本之间共享存储器的地址的集成。

我的问题:

1:这些方法中的任何一种都比从磁盘读取提供更快的访问权限吗? 认为跨进程/容器共享内存中的数据可以提高性能,是否甚至合理?

2:哪种方法最适合在多个Docker容器之间共享内存中的数据?

3:如何将Python的内存共享解决方案与docker run --ipc=集成在一起? (共享IPC名称空间甚至是跨Docker容器共享内存的最佳方法吗?)

4:是否有比这些更好的解决方案来解决我们的I / O开销大的问题?

最小工作示例-已更新。 不需要外部依赖!

这是我在单独容器中的Python脚本之间共享内存的幼稚方法。 当Python脚本在同一容器中运行时有效,但在单独的容器中运行时无效。

from import SyncManager

import multiprocessing

patch_dict = {}

image_level = 2

image_files = ['path/to/normal_042.tif']

region_list = [(14336, 10752),

(9408, 18368),

(8064, 25536),

(16128, 14336)]

def load_patch_dict():

for i, image_file in enumerate(image_files):

# We would load the image files here. As a placeholder, we just add `1` to the dict

patches = 1

patch_dict.update({'image_{}'.format(i): patches})

def get_patch_dict():

return patch_dict

class MyManager(SyncManager):

pass

if __name__ == "__main__":

load_patch_dict()

port_num = 4343

("patch_dict", get_patch_dict)

manager = MyManager(("127.0.0.1", port_num), authkey=b"password")

# Set the authkey because it doesn't set properly when we initialize MyManager

multiprocessing.current_process().authkey = b"password"

()

input("Press any key to kill server".center(50, "-"))

from import SyncManager

import multiprocessing

import sys, time

class MyManager(SyncManager):

pass

("patch_dict")

if __name__ == "__main__":

port_num = 4343

manager = MyManager(("127.0.0.1", port_num), authkey=b"password")

multiprocessing.current_process().authkey = b"password"

()

patch_dict = manager.patch_dict()

keys = list(patch_dict.keys())

for key in keys:

image_patches = patch_dict.get(key)

# Do NN stuff (irrelevant)

当这些脚本在同一容器中运行时,这些脚本可以很好地共享图像。 但是,当它们在单独的容器中运行时,如下所示:

# Run the container for the server

docker run -it --name cancer-1 --rm --cpus=10 --ipc=shareable cancer-env

# Run the container for the client

docker run -it --name cancer-2 --rm --cpus=10 --ipc=container:cancer-1 cancer-env

我收到以下错误:

Traceback (most recent call last):

File "patch_client.py", line 22, in

()

File "/usr/lib/python3.5/multiprocessing/", line 455, in connect

conn = Client(self._address, authkey=self._authkey)

File "/usr/lib/python3.5/multiprocessing/", line 487, in Client

c = SocketClient(address)

File "/usr/lib/python3.5/multiprocessing/", line 614, in SocketClient

(address)

ConnectionRefusedError: [Errno 111] Connection refused