2009-07-25 138 views
24

我一直在阅读关于Python的multiprocessing module。我仍然不认为我对它能做什么有很好的理解。Python:多核处理?

比方说,我有一个四核处理器,我有一个有1,000,000个整数的列表,我想要所有整数的总和。我可以简单地做:

list_sum = sum(my_list) 

但是,这只会将它发送到一个核心。

是否有可能使用多处理模块将数组分开,让每个内核都获得它的部分总和并返回值,以便可以计算总和?

喜欢的东西:

core1_sum = sum(my_list[0:500000])   #goes to core 1 
core2_sum = sum(my_list[500001:1000000]) #goes to core 2 
all_core_sum = core1_sum + core2_sum  #core 3 does final computation 

任何帮助,将不胜感激。

回答

30

是的,这是可能做到这一点求和几个过程,很像多线程做:

from multiprocessing import Process, Queue 

def do_sum(q,l): 
    q.put(sum(l)) 

def main(): 
    my_list = range(1000000) 

    q = Queue() 

    p1 = Process(target=do_sum, args=(q,my_list[:500000])) 
    p2 = Process(target=do_sum, args=(q,my_list[500000:])) 
    p1.start() 
    p2.start() 
    r1 = q.get() 
    r2 = q.get() 
    print r1+r2 

if __name__=='__main__': 
    main() 

然而,那么使用多个进程执行操作可能比在单个进程中执行操作要慢,因为向前和向后复制数据比立即求和要花费更多。

20

欢迎来到并发编程的世界。

Python可以(也不能)做什么取决于两件事情。

  1. 操作系统可以(也不可以)做什么。大多数操作系统将进程分配给内核。要使用4个内核,您需要将问题分解为四个进程。这比听起来容易。有时。

  2. 底层C库可以(也不可以)做什么。如果C库公开OS的功能并且操作系统公开了硬件的功能,那么您就是可靠的。

将问题分解为多个进程 - 特别是在GNU/Linux中 - 很容易。将其分解为多步骤流水线。

在总结一百万个数字的情况下,请考虑以下shell脚本。假设一些假设的sum.py程序在stdin上加上数字范围或数字列表。

(sum.py 0 500000 & sum.py 50000 1000000)| sum.py

这将有3个并发进程。两个人正在做很多数字的总和,第三个是总结两个数字。由于GNU/Linux shell和操作系统已经为你处理了一些并发的部分,你可以设计简单的(非常非常简单的)从stdin读取,写入标准输出的程序,并且设计用来完成小部分的一份大工作。

您可以尝试通过使用subprocess来构建管道而不是将作业分配给shell来降低开销。但是,您可能会发现,shell非常非常快地构建管道。 (它是用C直接编写并直接OS API调用你)

+0

我觉得这个答案显示了很多聪明才智。通过简单地添加一个间接层不能解决CS中的问题。 – earino 2009-07-25 16:54:24

+0

@earino:OTOH,它根本没有回答OP的问题,具体是关于“如何使用多处理模块”。 – 2009-07-25 18:34:56

7

当然,例如:

from multiprocessing import Process, Queue 

thelist = range(1000*1000) 

def f(q, sublist): 
    q.put(sum(sublist)) 

def main(): 
    start = 0 
    chunk = 500*1000 
    queue = Queue() 
    NP = 0 
    subprocesses = [] 
    while start < len(thelist): 
     p = Process(target=f, args=(queue, thelist[start:start+chunk])) 
     NP += 1 
     print 'delegated %s:%s to subprocess %s' % (start, start+chunk, NP) 
     p.start() 
     start += chunk 
     subprocesses.append(p) 
    total = 0 
    for i in range(NP): 
     total += queue.get() 
    print "total is", total, '=', sum(thelist) 
    while subprocesses: 
     subprocesses.pop().join() 

if __name__ == '__main__': 
    main() 

结果:

$ python2.6 mup.py 
delegated 0:500000 to subprocess 1 
delegated 500000:1000000 to subprocess 2 
total is 499999500000 = 499999500000 

注意,这粒度太细成为值得产卵过程 - 总求和任务是较小(这是为什么我可以重新计算总数作为支票;-),并且太多数据正在来回移动(事实上,子流程不需要获取他们工作的子列表的副本 - 索引就足够了)。所以,这是一个“玩具的例子”,其中多处理不是真正的保证。但是,对于不同的体系结构(使用从一个队列中接收多个任务的子进程池,最小化数据移动等等)和不太细化的任务,实际上可以在性能方面获得好处。