基本上,在下面的示例中,我想用列表中每个元素的位置填充五元素列表。我这样做是使用多处理。所以我希望即使填写列表的每次迭代都不会发生在更直观的顺序之后(从第一个元素到最后一个元素),最后列表仍然会被正确填充。这依赖于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
为什么会发生这种情况,即使用多处理时为什么没有通过引用传递的列表?
答案 0 :(得分:1)
如果你要做的只是填充列表,那么你应该尝试使用multiprocessing.Pool.map
。 map
的唯一问题是它在返回之前等待所有任务完成。因此,您可能希望探索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]