在Python 3.2中并行执行for循环

在Python 3.2中并行执行for循环,python,parallel-processing,python-3.x,multiprocessing,pickle,Python,Parallel Processing,Python 3.x,Multiprocessing,Pickle,可能重复: 我对Python(使用Python3.2)非常陌生,我有一个关于并行化的问题。我希望在Python 3.2中使用“多处理”并行执行一个for循环: def computation: global output for x in range(i,j): localResult = ... #perform some computation as a function of i and j output.append(local

可能重复:

我对Python(使用Python3.2)非常陌生,我有一个关于并行化的问题。我希望在Python 3.2中使用“多处理”并行执行一个for循环:

def computation:    
    global output

    for x in range(i,j):
        localResult = ... #perform some computation as a function of i and j
        output.append(localResult)
总之,我希望在I=0到j=100的范围内执行此计算。因此,我想创建一些进程,每个进程调用函数“computation”,其子域为总范围。你知道怎么做吗?有没有比使用多处理更好的方法

更具体地说,我想执行一个区域分解,我有以下代码:

from multiprocessing import Pool

class testModule:

    def __init__(self):
        self

    def computation(self, args):
        start, end = args
        print('start: ', start, ' end: ', end)

testMod = testModule()
length = 100
np=4
p = Pool(processes=np)
p.map(yes tMod.computation, [(length, startPosition, length//np) for startPosition in    range(0, length, length//np)]) 
我收到一条关于PicklingError的错误消息。你知道这里会有什么问题吗?

是专门为简单的并行循环而设计的多处理。我建议使用它,而不是直接处理多重处理

简单的情况如下所示:

from joblib import Parallel, delayed
Parallel(n_jobs=2)(delayed(foo)(i**2) for i in range(10))  # n_jobs = number of processes
一旦您理解了它,语法就很简单了。我们使用生成器语法,其中
delayed
用于调用函数
foo
,其参数包含在后面的括号中

在您的情况下,您应该使用生成器语法重写for循环,或者定义另一个函数(即“worker”函数)来执行单个循环迭代的操作,并将其放入调用Parallel的生成器语法中

在后一种情况下,您可以执行以下操作:

Parallel(n_jobs=2)(delayed(foo)(parameters) for x in range(i,j))

其中,
foo
是您定义的用于处理for循环主体的函数。请注意,您不希望附加到列表,因为Parallel无论如何都会返回一个列表。

在这种情况下,您可能需要定义一个简单的函数来执行计算并获取
localResult

def getLocalResult(args):
    """ Do whatever you want in this func.  
        The point is that it takes x,i,j and 
        returns localResult
    """
    x,i,j = args  #unpack args
    return doSomething(x,i,j)
现在,在计算函数中,您只需创建一个工人池并映射本地结果:

import multiprocessing
def computation(np=4):
    """ np is number of processes to fork """
    p = multiprocessing.Pool(np)
    output = p.map(getLocalResults, [(x,i,j) for x in range(i,j)] )
    return output
我在这里删除了global,因为它是不必要的(global通常是不必要的)。在调用例程中,只需执行
output.extend(计算(np=4))
或类似操作

编辑

下面是代码的“工作”示例:

from multiprocessing import Pool

def computation(args):
    length, startPosition, npoints = args
    print(args)

length = 100
np=4
p = Pool(processes=np)
p.map(computation, [(startPosition,startPosition+length//np, length//np) for startPosition in  range(0, length, length//np)])

请注意,由于使用实例方法作为函数,所以您所做的工作不起作用。多处理启动新进程,并通过
pickle
在进程之间发送信息,因此,只能使用可以pickle的对象。请注意,无论如何使用实例方法是没有意义的。每个进程都是父进程的副本,因此进程中发生的任何状态更改都不会传播回父进程

您在for循环中实际进行了多少计算?如果它是一个依赖于i和j的简单表达式,那么创建多个进程/线程的开销将远远超过并行计算的好处。这是一个相当繁重的计算,涉及调用其他几个函数。循环是完全并行的,所以我肯定需要创建多个进程/线程。在谷歌上搜索
python parallelize for loop
只需几秒钟就可以找到
joblib
。@SvenMarnach,我不相信这是重复的。OP还询问是否有一种更简单的方法来解决他的问题,并且前面的问题中没有包括诸如
joblib
之类的选项。@blz:在对另一个问题的回答中没有人提到
jiblib
这一事实并不意味着它不是重复的-你可以很容易地在那里添加相同的答案。很高兴听到这个消息!你介意检查一下我的最后一个例子吗?我不能完全确定是否要以这种方式调用
list.append
,实际上我还没有测试我的代码。虽然它应该有效。。。理论上,方法调用与独立函数没有什么不同。@blz:这是不可能的。
delayed
的参数必须是可拾取的。而且,这样做没有意义,因为
Parallel
无论如何都会返回一个列表。@larsmans,Yikes。。。我需要多睡一会儿。我将进行编辑。您应该提供一个处理单个项目的辅助函数:即接受
x
作为参数。
delayed
的第二个参数是
x
@phant0m,谢谢!编辑已经完成。我可能应该去喝点咖啡=/很抱歉不够清楚,但是在函数getLocalResult中,我需要知道每个进程工作的时间间隔。假设总间隔是从0到100,我使用4个进程,局部间隔由iLocal和jLocal给出。然后对于第一个进程,iLocal=0和jLocal=25,对于第二个进程,iLocal为26,jLocal为50,依此类推。目前,我假设x代表iLocal,但我怎么知道子进程操作的时间间隔的结束?@user1499144——你在做某种区域分解吗?如果是这样的话,您可以将列表理解替换为如下内容:
[(i,100//np)for i in range(0100100//np)]
--然后在“getLocalResult”中有一个
for
循环。域分解正是我要做的!但是,在考虑了您的评论之后,我仍然无法让它工作,您可以在下面的答案中看到我的全部代码。我编辑了上面的原始问题,以便您可以看到不工作的代码。非常感谢您的任何意见!太好了,非常感谢!你让我开心!