在Python中使用多处理时,为什么数组不能通过引用传递?

时间:2015-08-18 13:44:02

标签: python multiprocessing python-multiprocessing

基本上,在下面的示例中,我想用列表中每个元素的位置填充五元素列表。我这样做是使用多处理。所以我希望即使填写列表的每次迭代都不会发生在更直观的顺序之后(从第一个元素到最后一个元素),最后列表仍然会被正确填充。这依赖于arr通过引用传递的假设,因此实际上每次调用函数f时都可以改变它。但是,arr永远不会改变,当我们将它打印出来时,它仍然是初始化的,即[0] * 5 = [0,0,0,0,0]。

from joblib import Parallel, delayed
import multiprocessing

arr = [0]*5
cases = [0,1,2,3,4]

def f(arr, position):
    arr[position] = position


num_cores = multiprocessing.cpu_count()

Parallel(n_jobs=num_cores)(delayed(f)(arr, position) for position in cases) 

print arr 

当我们不使用多处理时,我们得到预期的结果:

def f(arr, position):
arr[position] = position

arr = [0]*5

for i, el in enumerate(arr):
    f(arr, i)

print arr

为什么会发生这种情况,即使用多处理时为什么没有通过引用传递的列表?

1 个答案:

答案 0 :(得分:1)

如果你要做的只是填充列表,那么你应该尝试使用multiprocessing.Pool.mapmap的唯一问题是它在返回之前等待所有任务完成。因此,您可能希望探索imap替代方案。可能每个任务花费的时间基本上不同。在这种情况下,请查看imap_unordered(其中我还包括了一个示例)。

例如

from multiprocessing import Pool
from contextlib import closing

def f(n):
    return n * 2

def g(args):
    id_, n = args
    return id_, -n

if __name__ == "__main__":
    cases = range(5)
    # Pool automatically uses the same number of subprocesses as cpu_count
    with closing(Pool()) as pool:
        arr = pool.map(f, cases)
    print(arr) # prints [0, 2, 4, 6, 8]

    arr = [None] * len(cases)
    with closing(Pool()) as pool:
        for idx, result in pool.imap_unordered(g, enumerate(cases)):
            arr[idx] = result
    print(arr) # prints [0, -1, -2, -3, -4]