问题 结合itertools和多处理?


我有一个 256x256x256 Numpy数组,其中每个元素都是一个矩阵。我需要对这些矩阵中的每一个进行一些计算,我想使用 multiprocessing 模块加快速度。

这些计算的结果必须存储在一个 256x256x256 数组与原始数组一样,因此矩阵元素的结果 [i,j,k] 在原始数组中必须放入 [i,j,k] 新数组的元素。

为此,我想制作一个可以用伪方式编写的列表 [array[i,j,k], (i, j, k)] 并将其传递给一个“多处理”的函数。 假如说 matrices 是从原始数组中提取的所有矩阵的列表 myfunc 是进行计算的函数,代码看起来有点像这样:

import multiprocessing
import numpy as np
from itertools import izip

def myfunc(finput):
    # Do some calculations...
    ...

    # ... and return the result and the index:
    return (result, finput[1])

# Make indices:
inds = np.rollaxis(np.indices((256, 256, 256)), 0, 4).reshape(-1, 3)

# Make function input from the matrices and the indices:
finput = izip(matrices, inds)

pool = multiprocessing.Pool()
async_results = np.asarray(pool.map_async(myfunc, finput).get(999999))

但是,好像 map_async 实际上创造了这个巨大的 finput-list first:我的CPU没有做太多,但是内存和交换在几秒钟内完全耗尽,这显然不是我想要的。

有没有办法将这个庞大的列表传递给多处理函数而无需先显式创建它? 或者你知道另一种解决这个问题的方法吗?

谢谢你! :-)


2113
2017-09-05 10:05


起源

因为你正在使用 get() 上 map_async(),你可能不想要一个 异步 操作并应该使用 Pool.map() 代替。 - Ferdinand Beyer
也许我没有正确理解这个问题,但你考虑过imap或imap_unordered吗? - Torsten Marek


答案:


所有 multiprocessing.Pool.map* 方法完全消耗迭代器(演示代码)


10
2017-09-05 11:22



非常感谢你!您的解决方案似乎确实有效!作为参考,我不得不使用pool.map_async(myfunc,finput).get(999999),但它有效!但是,它仍然使用大量内存(当然取决于确切的chunksize),并且python在运行期间似乎不是垃圾收集。任何想法为什么会这样? - digitaldingo
@digitaldingo:嗯,什么都没想到。如果你可以将你的代码减少到一个,那将是理想的 SSCCE 并在此发布。 - unutbu


我也遇到了这个问题。而不是这个:

res = p.map(func, combinations(arr, select_n))

res = p.imap(func, combinations(arr, select_n))

imap不消耗它!


2
2018-01-14 15:38





Pool.map_async() 需要知道迭代的长度,以便将工作分配给多个工作者。以来 izip 没有 __len__,它首先将iterable转换为列表,导致您遇到的巨大内存使用量。

您可以尝试通过创建自己的方法来回避这一点 izip-style迭代器 __len__


0
2017-09-05 11:00



为什么需要知道呢?为什么不能简单地为所有闲置工人和等待人员提供食物? - andrew cooke
@andrew - 第一行 map_async() (multiprocessing/pool.py)实际上是 if not hasattr(iterable, '__len__'): iterable = list(iterable)。它需要知道创建足够大的输出列表的长度,因为工人的完成顺序是未知的。 - Ferdinand Beyer
嗯。它可以动态构建,不是吗?我只是觉得这可能会成为一个问题。这似乎是一个有效的请求。 - andrew cooke
是的,它可以没有 __len__ 但这会很复杂。如果结果#321在#23之前就绪,那么它应该存储在哪里?如果知道长度,这会变得更容易。 - Ferdinand Beyer
bugs.python.org/msg143511 - andrew cooke