Jac*_*ern 14 python ipc shared-memory docker python-multiprocessing
我已经编写了一个神经网络分类器,该分类器可以获取海量图像(每张图像约1-3 GB),对其进行修补,然后分别将修补程序通过网络。培训的进行非常缓慢,因此我对其进行了基准测试,发现花大约50 秒钟的时间将补丁从一个图像加载到内存中(使用Openslide库),而仅需0.5秒钟就可以将它们通过模型。
但是,我正在使用具有1.5Tb RAM的超级计算机,其中仅使用了约26 Gb。数据集总计约500Gb。我的想法是,如果我们可以将整个数据集加载到内存中,它将极大地加快训练速度。但是我正在与一个研究团队合作,我们正在多个Python脚本之间进行实验。因此,理想情况下,我想将一个脚本中的整个数据集加载到内存中,并能够在所有脚本中对其进行访问。
更多细节:
.tif格式存储。我发现了很多关于如何在多个Python脚本之间共享Python对象或内存中的原始数据的文章:
多处理模块中具有SyncManager和BaseManager的服务器进程| 示例1 | 示例2 | Docs-服务器进程 | 文件-SyncManager
Manager对象在发送对象之前先对其进行腌制,这可能会使事情变慢。mmap将文件映射到虚拟内存,而不是物理内存 -它会创建一个临时文件。适用于Python 的sysv_ipc模块。这个演示看起来很有希望。
multi-processing模块中可用的功能?我还在Python中找到了IPC /网络选项列表。
有些人讨论服务器-客户端设置,有些人讨论序列化/反序列化,这恐怕会比从磁盘读取花费更多的时间。我找不到任何答案可以解决我的问题,这些答案是否会导致I / O性能的提高。
我们不仅需要在脚本之间共享Python对象/内存;我们需要在Docker容器之间共享它们。
Docker 文档--ipc很好地解释了该标志。根据文档的运行情况,对我来说有意义的是:
docker run -d --ipc=shareable data-server
docker run -d --ipc=container:data-server data-client
Run Code Online (Sandbox Code Playgroud)
但是,当我在--ipc如上所述建立连接的单独容器中运行客户机和服务器时,它们无法相互通信。我读过SO问题(1,2,3,4)不以单独的Docker容器Python脚本之间共享存储器的地址的集成。
docker run --ipc=<mode>?(共享IPC名称空间甚至是跨Docker容器共享内存的最佳方法吗?)这是我在单独容器中的Python脚本之间共享内存的幼稚方法。当Python脚本在同一容器中运行时有效,但在单独的容器中运行时无效。
server.py
docker run -d --ipc=shareable data-server
docker run -d --ipc=container:data-server data-client
Run Code Online (Sandbox Code Playgroud)
client.py
from multiprocessing.managers 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
MyManager.register("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"
manager.start()
input("Press any key to kill server".center(50, "-"))
manager.shutdown
Run Code Online (Sandbox Code Playgroud)
当这些脚本在同一容器中运行时,这些脚本可以很好地共享图像。但是,当它们在单独的容器中运行时,如下所示:
# 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
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
from multiprocessing.managers import SyncManager
import multiprocessing
import sys, time
class MyManager(SyncManager):
pass
MyManager.register("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"
manager.connect()
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 Code Online (Sandbox Code Playgroud)
我建议您尝试使用tmpfs。
它是一项Linux功能,可让您创建一个虚拟文件系统,所有文件系统都存储在RAM中。这样可以非常快速地访问文件,并且只需设置一个bash命令即可。
除了非常快速和直接之外,它在您的情况下还具有许多优点:
cp将数据集放入tmpfstmpfs可以调整页面并将其交换到硬盘驱动器。如果您必须在没有可用RAM的服务器上运行此文件,则可以将所有文件都放在具有普通文件系统的硬盘驱动器上,而根本不用触摸代码。使用步骤:
sudo mount -t tmpfs -o size=600G tmpfs /mnt/mytmpfscp -r dataset /mnt/mytmpfsramfs可能比tmpfs某些情况下要快,因为它没有实现页面交换。要使用它,只需更换tmpfs与ramfs上面的说明。
我认为shared memory或mmap解决方案是正确的。
共享内存:
首先在服务器进程中读取内存中的数据集。对于Python,只需使用multiprocessing包装器在进程之间的共享内存中创建对象,例如:multiprocessing.Value或multiprocessing.Array,然后创建 Process 并将共享对象作为参数传递。
映射:
将数据集存储在主机上的文件中。然后每个容器将文件挂载到容器中。如果一个容器打开该文件并将该文件映射到其虚拟内存中,则其他容器在打开该文件时无需将文件从磁盘读取到内存,因为该文件已经在物理内存中。
PS我不确定cpython如何实现进程之间的大共享内存,可能cpython共享内存使用mmap内部。
| 归档时间: |
|
| 查看次数: |
526 次 |
| 最近记录: |