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

Why are arrays not passed by reference when using Multiprocessing in Python?

基本上,在下面的示例中,我想用列表中每个元素的位置填充一个五元素列表。我正在使用多处理来做到这一点。所以我希望即使每次填充列表的迭代可能不会按照更直观的顺序(从第一个元素到最后一个元素)发生,最终列表仍然会被正确填充。这依赖于 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

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

如果您只想填充列表,那么您应该尝试使用 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]