尝试并行化嵌套for循环并保存中间结果

0 投票
2 回答
786 浏览
提问于 2025-04-17 23:53

我对并行处理完全是个新手。我想要把一个嵌套的for循环进行并行处理,并存储一些中间结果。这些结果来自一个函数f,这个函数需要一些正式的参数和一些全局变量的值。我在这里得到了些建议,比如我可以使用itertools来生成一个笛卡尔积,这样就相当于一个嵌套循环。但似乎并没有效果。我想存储中间结果的数组没有变化。我附上了一个最小的可工作示例。

操作系统:Windows 7 64位

Python版本:Canopy Enthought

import itertools
import numpy as np
from multiprocessing import Pool

list1 = range(4, 8)
list2 = range(6, 9)
ary = np.zeros( (len(list1), len(list2)) )

#This is the archetypical function f. It DOES NOT have p2 as a parameter! This
#is intended! In my (more complex) program a function f calls somewhere deep
#down another function that gets its values from global variables. Rewriting
#the code to hand down the variables as parameters would turn my code into a mess.
def f(p1):
    return p1*p2

#This is what I want to parallelize: a nested loop, where the result of f is saved
#in an array element corresponding to the indices of p1 and p2.
#for p1 in list1:
#    for p2 in list2:
#        i = list1.index(p1)
#        j = list2.index(p2)
#        ary[i,j]=f(p1)

#Here begins the try to parallelize the nested loop. The function g calls f and
#does the saving of the results. g takes a tuple x, unpacks it, then calculates
#f and saves the result in an array.
def g(x):
    a, b = x
    i = list1.index(a)
    j = list2.index(b)
    global p2
    p2 = b
    ary[i,j] = f(a)

if __name__ == "__main__":
    #Produces a cartesian product. This is equivalent to a nested loop.
    it = itertools.product(list1, list2)
    pool = Pool(processes=2)
    result = pool.map(g, it)
    print ary
    #Result: ary does not change!

2 个回答

0

你需要通过某种方式在不同的进程之间共享信息。比如可以看看multiprocessing.queue这个东西。

如果你想使用共享内存,那就得用线程(threading)了。虽然全局解释器锁(GIL)会影响线程的性能,但你可能还是能让numpy的命令并行运行。

1

通过使用 Pool,你的程序会复制出多个进程,每个进程都有自己的全局变量。当你的计算完成后,主进程的全局变量并没有改变。

你应该使用你并行调用的函数的返回值,并把结果结合起来,也就是说,要使用你在代码中提到的 result 变量。

result = pool.map(g, it)

在你的情况下,它目前只包含了一堆 None

关于并行计算的一个通用建议是:始终使用纯计算,也就是说,不要依赖像全局变量这样的副作用。

撰写回答