2014-01-09 68 views
2

最近我想用并行处理来加速我的一些代码,因为我有一个四核酷睿i7,它看起来很浪费。我学会了Python的(我用V 3.3.2如果事宜中)GIL以及如何使用多模块来克服,所以我写了这个简单的测试程序:Python多重处理故障排除

from multiprocessing import Process, Queue 

def sum(a,b): 
    su=0 
    for i in range(a,b): 
     su+=i 
    q.put(su) 

q= Queue() 

p1=Process(target=sum, args=(1,25*10**7)) 
p2=Process(target=sum, args=(25*10**7,5*10**8)) 
p3=Process(target=sum, args=(5*10**8,75*10**7)) 
p4=Process(target=sum, args=(75*10**7,10**9)) 

p1.run() 
p2.run() 
p3.run() 
p4.run() 

r1=q.get() 
r2=q.get() 
r3=q.get() 
r4=q.get() 

print(r1+r2+r3+r4) 

的代码在约48运行秒使用cProfile测量,但单个处理代码

def sum(a,b): 
    su=0 
    for i in range(a,b): 
     su+=i 
    print(su) 

sum(1,10**9) 

在约50秒内运行。我知道这种方法有开销,但我预计改进会更加激烈。使用fork()的error不适用于我,因为我在Mac上运行代码。

+2

你看了并行运行时的CPU负载?有几个核心加载? – 9000

+0

是的,所有4个核心中的活动都刺激了,奇怪的是在序列情况下也是如此。活动监视器也声称python只使用1个线程,通过计算中途切换到2(在并行的情况下) – Michal

+0

'multiprocessing'启动单独的_processes_,它在Activity Monitor中获取单独的行(通常都称为“Python”) 。 – abarnert

回答

6

问题是你打电话给run而不是start

如果您阅读文档,run是“表示过程活动的方法”,而start是启动过程在后台进程上的活动的函数。 (这与threading.Thread相同。)

因此,您所做的是在主进程上运行sum函数,并且从不在后台进程上执行任何操作。

从我笔记本电脑的计时测试中,可以将时间缩短到原来的37%左右。不是你希望的25%,我不确定为什么,但是......足以证明它确实是多处理。 (这和事实,我得到四个额外Python进程每个使用60-100%的CPU ......)

+0

哇,下降到20秒,并不是4倍的希望,但无论如何欢迎。 :D – Michal

+0

@Michal:看起来我和你同时进行了同样的测试,结果几乎相同(37%比40%)。我对此有些好奇(在大部分工作中绝对没有争用,很少使用内存......),但还不足以深入挖掘。 – abarnert

2

如果你真的想用python编写快速计算它不是要走的路。使用numpy或cython。你的计算速度比普通Python快上百倍。

。如果您只是想推出一堆parralel工作使用正确的工具,它另一方面,例如

from multiprocessing import Pool 

def mysum(a,b): 
    su=0 
    for i in range(a,b): 
    su+=i 
    return su 

with Pool() as pool: 
    print(sum(pool.starmap(mysum, ((1,25*10**7), 
           (25*10**7,5*10**8), 
           (5*10**7,75*10**7), 
           (75*10**7,10**9))))) 
+0

您的示例实际上并未返回值,因此无法在最后打印出来。看到[这里](http://pastebin.com/A56ThhSk)的代码(并且干净地关闭了池)。 – abarnert

+0

你的方式更好;) –

+0

另一方面,你原来的方式会更容易适应'imap_unordered'(在这种情况下这可能是值得的 - 如果我们正在做的事情没有理由返回结果正在添加它们),因为没有'istarmap_unordered' ... – abarnert