我一直在阅读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
任何帮助,将不胜感激.
是的,可以对多个进程进行总结,非常类似于使用多个线程:
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()
但是,使用多个进程执行此操作可能比在单个进程中执行此操作要慢,因为前后复制数据比立即汇总数据要昂贵.
欢迎并发编程的世界.
Python可以(也可以不)做的事情取决于两件事.
操作系统可以(也可以不)做什么.大多数操作系统将进程分配给核心.要使用4个内核,您需要将问题分解为四个进程.这比听起来容易.有时.
底层C库可以(也可以不)做什么.如果C库暴露了操作系统的功能,并且操作系统公开了硬件的功能,那么您就是可靠的.
将问题分解为多个进程 - 特别是在GNU/Linux中 - 很容易.将其分解为多步骤管道.
在汇总一百万个数字的情况下,请考虑以下shell脚本.假设一些假设sum.py
程序将stdin上的数字范围或数字列表相加.
(sum.py 0 500000&sum.py 50000 1000000)| sum.py
这将有3个并发进程.两个正在做很多数字的总和,第三个是两个数字相加.
由于GNU/Linux shell和操作系统已经为您处理了并发的某些部分,因此您可以设计简单(非常非常简单)的程序,这些程序从stdin读取,写入stdout,并且设计用于执行大型作业的一小部分.
您可以尝试通过使用子进程来构建管道而不是将作业分配给shell 来减少开销.但是,您可能会发现shell非常快速地构建管道.(它直接用C语言编写,并为您提供直接的OS API调用.)
当然,例如:
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
请注意,这个粒度太精细,不值得产生进程 - 整体求和任务很小(这就是为什么我可以重新计算main中的总和作为一个检查;-)并且来回移动太多数据(在事实上,子流程不需要获得他们所使用的子列表的副本 - 索引就足够了.因此,它是一个"玩具示例",其中多处理并不是真正的保证.使用不同的体系结构(使用从队列接收多个任务的子进程池,来回最小化数据移动等),然而在不太精细的任务上,您实际上可以获得性能方面的好处.