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

Python 尝试并行嵌套for循环并保存中间结果,python,arrays,numpy,parallel-processing,Python,Arrays,Numpy,Parallel Processing,我完全不熟悉并行化。我想并行化嵌套的for循环并存储一些中间结果。结果来自一个函数f,它从全局变量中获取一些形式参数和一些值。我从中得到了一些建议,例如,我使用itertools生成了一个笛卡尔积,它相当于一个嵌套循环。但它似乎不起作用。要存储中间结果的数组保持不变。附上一个最简单的工作示例 操作系统:Windows 7 64位 Python发行版:Croopy Enthow import itertools import numpy as np from multiprocessing imp

我完全不熟悉并行化。我想并行化嵌套的for循环并存储一些中间结果。结果来自一个函数f,它从全局变量中获取一些形式参数和一些值。我从中得到了一些建议,例如,我使用itertools生成了一个笛卡尔积,它相当于一个嵌套循环。但它似乎不起作用。要存储中间结果的数组保持不变。附上一个最简单的工作示例

操作系统:Windows 7 64位

Python发行版:Croopy Enthow

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!

通过使用
,程序会以某种方式复制进程的次数,每个进程都有自己的全局变量。当计算返回时,主进程的全局变量没有改变。 您应该使用并行调用的函数的返回值并组合结果,也就是说,使用变量
result
from行

result = pool.map(g, it)
在您的情况下,它只包含一个到目前为止的
None
s列表


并行化的一般提示:始终使用纯计算,这意味着不要依赖全局变量等副作用。

您需要使用某种机制在进程之间共享信息。以multiprocessing.queue为例


如果要使用共享内存,则需要使用线程。您可能会发现,虽然GIL确实会影响线程性能,但您仍然可以并行运行numpy命令。

好的,所以您说我不应该依赖ary的“全局性”。很好,我用
return(I,j,f(a))
替换了g()ary[I,j]=f(a)的定义,然后结果不包含'None',我可以从结果构造ary。我定义了一个函数
def constr(x):I,j,val=x ary[I,j]=val
,然后我可以在结果上映射构造并得到ary。它起作用了!非常感谢。关于全局性:行
global p2 p2=b
是否会导致争用条件,即一个进程由于另一个进程更改了其(全局值)而获得p2的“错误”值?@David:如果你接受我的答案,那就太好了。对于您的评论:我认为,这不会发生,但是再次出现了一个
全局
,请尝试重写它。我做了一个测试:我在代码的开头设置了p2=0。然后执行并行部分。ary构造正确,p2的(全局)值保持为0。我假设每个进程都获得一个list1、list2、ari、p2等的副本,并且可以在不修改原始进程或其他进程副本的情况下对其进行修改。这似乎有效,但对我来说还是有点神奇。没有“全局”我无法重写真正的代码,因为需要这些全局值的函数嵌套在其他函数的深处。重写现有代码将是一场噩梦,其好处远远超过了它。您可以将所有导入移动到主块。这将更清楚地表明,每个进程运行脚本的第一部分,而只有主进程运行最后一个块。因此,每个进程都会创建自己的list1、list2等副本。它从
获得的只是
g
的输入。共享内存不需要线程。共享内存也可以用于多个进程。例如,使用SysV shm_get或POSIX shm_open从分页文件(Windows上为fd 0或Linux上为-1)获得mmap.mmap,Linux上为/tmp获得mmap。一旦有了缓冲区,就可以使用它来支持指向共享内存的NumPy数组(NumPy.frombuffer)。多处理。数组也可以用作NumPy的共享内存缓冲区。这不是有点像用大锤打死苍蝇吗?线程、队列等都有同步方法,这是最初的问题。使用multiprocessing.Array作为输出数组的缓冲区可以解决这个问题。它不会更新,因为它是进程的本地文件。把它放在共享内存中是一种可能的补救办法。由于GIL,线程不能用于计算任务的并行化。Python线程可以并行化阻塞的i/o操作,但不能并行化CPU密集型工作。