Python 多进程并发操作中进程池Pool的实例
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,10几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,这时候进程池Pool发挥作用的时候就到了。
Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。这里有一个简单的例子:
#!/usr/bin/envpython #coding=utf-8 """ Author:Squall Lastmodified:2011-10-1816:50 Filename:pool.py Description:asimplesampleforpoolclass """ frommultiprocessingimportPool fromtimeimportsleep deff(x): foriinrange(10): print'%s---%s'%(i,x) sleep(1) defmain(): pool=Pool(processes=3)#settheprocessesmaxnumber3 foriinrange(11,20): result=pool.apply_async(f,(i,)) pool.close() pool.join() ifresult.successful(): print'successful' if__name__=="__main__": main()
先创建容量为3的进程池,然后将f(i)依次传递给它,运行脚本后利用psaux|greppool.py查看进程情况,会发现最多只会有三个进程执行。pool.apply_async()用来向进程池提交目标请求,pool.join()是用来等待进程池中的worker进程执行完毕,防止主进程在worker进程结束前结束。但必pool.join()必须使用在pool.close()或者pool.terminate()之后。其中close()跟terminate()的区别在于close()会等待池中的worker进程执行结束再关闭pool,而terminate()则是直接关闭。result.successful()表示整个调用执行的状态,如果还有worker没有执行完,则会抛出AssertionError异常。
利用multiprocessing下的Pool可以很方便的同时自动处理几百或者上千个并行操作,脚本的复杂性也大大降低。
——————————————————————————————————
Python多进程并发(multiprocessing)
由于Python设计的限制(我说的是咱们常用的CPython)。最多只能用满1个CPU核心。
Python提供了非常好用的多进程包multiprocessing,你只需要定义一个函数,Python会替你完成其他所有事情。借助这个包,可以轻松完成从单进程到并发执行的转换。
1、新建单一进程
如果我们新建少量进程,可以如下:
importmultiprocessing importtime deffunc(msg): foriinxrange(3): printmsg time.sleep(1) if__name__=="__main__": p=multiprocessing.Process(target=func,args=("hello",)) p.start() p.join() print"Sub-processdone."
2、使用进程池
是的,你没有看错,不是线程池。它可以让你跑满多核CPU,而且使用方法非常简单。
注意要用apply_async,如果落下async,就变成阻塞版本了。
processes=4是最多并发进程数量。
import multiprocessing import time def func(msg): for i in xrange(3): print msg time.sleep(1) if __name__ == "__main__": pool = multiprocessing.Pool(processes=4) for i in xrange(10): msg = "hello %d" %(i) pool.apply_async(func, (msg, )) pool.close() pool.join() print "Sub-process(es) done."
3、使用Pool,并需要关注结果
更多的时候,我们不仅需要多进程执行,还需要关注每个进程的执行结果,如下:
importmultiprocessing importtime deffunc(msg): foriinxrange(3): printmsg time.sleep(1) return"done"+msg if__name__=="__main__": pool=multiprocessing.Pool(processes=4) result=[] foriinxrange(10): msg="hello%d"%(i) result.append(pool.apply_async(func,(msg,))) pool.close() pool.join() forresinresult: printres.get() print"Sub-process(es)done."
2014.12.25更新
根据网友评论中的反馈,在Windows下运行有可能崩溃(开启了一大堆新窗口、进程),可以通过如下调用来解决:
multiprocessing.freeze_support()
简易workermultiprocessing.Pool
多任务模型设计是一个比较复杂的逻辑,但是python对于多任务的处理却有种种方便的类库,不需要过多的纠结进程/线程间的操作细节。比如multiprocessing.Pool就是其中之一。
官方给的范例也很简单。
frommultiprocessingimportPool deff(x): returnx*x if__name__=='__main__': pool=Pool(processes=4)#start4workerprocesses result=pool.apply_async(f,[10])#evaluate"f(10)"asynchronously printresult.get(timeout=1)#prints"100"unlessyourcomputeris*very*slow printpool.map(f,range(10))#prints"[0,1,4,...,81]"
并未做太多的详细解释。正好我手头有一段代码,需要请求几百个url,解析html页面获取一些信息,单线程for循环效率极低,因此看到了这个模块,想用这个实现多任务分析,参考代码如下:
frommultiprocessingimportPool defanalyse_url(url): #dosomethingwiththisurl returnanalysis_result if__name__=='__main__': pool=Pool(processes=10) result=pool.map(analyse_url,url_list)
确实比以前单线程for循环url_list列表,一个个请求analyse_url要快得多,但是带来的问题就是一旦pool.map没执行完就ctrl-c中断程序,程序就会异常,永远无法退出,参考stackoverflow的这个帖子,修改为以下代码:
#result=pool.map(analyse_url,url_list) result=pool.map_async(analyse_url,url_list).get(120)
至此问题完美解决。
以上这篇Python多进程并发操作中进程池Pool的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。