在Python中,何时将map()与multiprocessing.Pool一起使用,何时不使用?输入值大的情况

在Python中,何时将map()与multiprocessing.Pool一起使用,何时不使用?输入值大的情况,python,dictionary,parallel-processing,multiprocessing,large-data,Python,Dictionary,Parallel Processing,Multiprocessing,Large Data,在每个输入值都很大(比如500 MB)但输入值通常包含相同的大对象的情况下,使用multiprocessing.Pool.map()并行计算多个结果是否有效?我担心,多处理的工作方式是向池中的每个工作进程发送每个输入值的pickle版本。如果未执行优化,这将意味着为map()中的每个输入值发送大量数据。是这样吗?我很快查看了多处理代码,但没有发现任何明显的问题 更一般地说,您会推荐什么简单的并行化策略,以便对10000个值执行map(),每个值都是元组(向量,非常大的矩阵),其中向量总是不同的,

在每个输入值都很大(比如500 MB)但输入值通常包含相同的大对象的情况下,使用
multiprocessing.Pool.map()
并行计算多个结果是否有效?我担心,
多处理
的工作方式是向池中的每个工作进程发送每个输入值的pickle版本。如果未执行优化,这将意味着为
map()
中的每个输入值发送大量数据。是这样吗?我很快查看了
多处理
代码,但没有发现任何明显的问题

更一般地说,您会推荐什么简单的并行化策略,以便对10000个值执行
map()
,每个值都是元组
(向量,非常大的矩阵)
,其中向量总是不同的,但是只有5个不同的非常大的矩阵


PS:大的输入矩阵实际上是“渐进式”出现的:2000个向量首先与第一个矩阵一起发送,然后2000个向量与第二个矩阵一起发送,等等。

我认为显而易见的解决方案是发送对非常大的矩阵的引用,而不是对象本身的克隆?如果只有五个大矩阵,请在主流程中创建它们。然后,当实例化
multiprocessing.Pool
时,它将创建许多子进程来克隆父进程的地址空间。这意味着,如果池中有六个进程,那么内存中将同时有(1+6)*5个不同的矩阵

因此,在主流程中,创建所有唯一矩阵的查找:

matrix_lookup = {1 : matrix(...), 2 : matrix(...), ...}
然后将
矩阵_查找中每个矩阵的索引与向量一起传递给辅助进程:

p = Pool(6)
pool.map(func, [(vector, 1), (vector, 2), (vector, 1), ...])

我遇到了一个类似的问题:在大数据集上并行计算。正如您提到的,
multiprocessing.Pool.map
pickle参数。我所做的是实现我自己的
fork()
包装器,它只将返回值pickle回父进程,从而避免pickle参数。还有一个并行的
map()
,放在包装器的顶部。

我想这可能就是您想要的答案。谢谢您的输入。您提到的问题与此问题之间的区别在于,大型矩阵本质上是map的输入值(链接到的问题仅使用单个大型对象)。此外,上面答案中的任何解决方案似乎都不适合这个问题,这听起来是个好主意。但我有一个问题:可怕的写拷贝诅咒最终会在每个过程中强制每个大型矩阵的拷贝吗?我读到Python的对象引用计数与对象一起存储:通过引用一个对象来增加引用计数会将整个对象复制到分叉进程中(在大多数操作系统下——如果我理解正确的话,Windows会更糟)。是的,可怕的写时复制会做到这一点。但是,对于传递给map()的列表中的每一项,内存中有5*(P+1)个矩阵(其中P是池中的进程数)远远少于一个矩阵。感谢您确认写入时复制。我不知道我是否理解为什么“传递给map()的列表中的项”使用的内存比内存中有5*(P+1)个矩阵“多得多”。事实上,列表的内存占用基本上是5个矩阵的大小,小于5*(P+1)矩阵的大小(原因是Python在内部使用指向5个矩阵的指针)。所有进程是否都复制了大数据集?如果我理解正确的话,你有一个大数据集:问题是关于有几个大数据集(目前已有针对单个大数据集的解决方案,你甚至可能想添加你的解决方案)。PS:这里是对“写时复制”的引用只读对象的内存复制:。这是python引用计数导致在
fork
ed子对象中复制页面的一个很好的观点。