Python多进程并发操作:进程池Pool实例详解
本文详解Python中multiprocessing模块的进程池Pool用法。通过实例展示如何创建指定数量进程的池,利用apply_async进行异步提交,并处理close、join及结果获取。涵盖Windows崩溃修复、Ctrl-C中断退出等常见问题,帮助高效实现多核CPU并行计算。
在利用Python进行系统管理时,尤其是涉及同时操作多个文件目录或远程控制多台主机的场景,并行操作能显著节约时间。当目标对象数量较少时,可直接使用multiprocessing模块中的Process动态生成多个进程,处理十几个任务尚可;但若面对上百甚至上千个目标,手动限制进程数量又过于繁琐,此时进程池Pool便派上了用场。
进程池Pool可提供指定数量的进程供用户调用。当有新请求提交到Pool时,若池未满,则创建新进程执行该请求;若池内进程数已达规定最大值,请求将进入等待状态,直到有进程结束,系统才会创建新进程来执行它。以下是一个简单示例:
#!/usr/bin/env python
#coding=utf-8
"""
Author: Squall
Last modified: 2011-10-18 16:50
Filename: pool.py
Description: a simple sample for pool class
"""
from multiprocessing import Pool
from time import sleep
def f(x):
for i in range(10):
print '%s --- %s ' % (i, x)
sleep(1)
def main():
pool = Pool(processes=3) # set the processes max number 3
for i in range(11,20):
result = pool.apply_async(f, (i,))
pool.close()
pool.join()
if result.successful():
print 'successful'
if __name__ == "__main__":
main()
首先创建一个容量为3的进程池,随后将函数f(i)依次传递给它。运行脚本后,通过命令ps aux | grep pool.py查看进程状态,会发现最多仅有三个进程在执行。pool.apply_async()用于向进程池提交目标请求,而pool.join()用于等待进程池中的worker进程执行完毕,以防止主进程在worker结束前退出。需要注意的是,pool.join()必须放置在pool.close()或pool.terminate()之后。两者的区别在于,close()会等待池中的worker进程执行完毕后再关闭Pool,而terminate()则是直接强制关闭。result.successful()表示整个调用的执行状态,若仍有worker未执行完,则会抛出AssertionError异常。
利用multiprocessing模块下的Pool,可以方便地同时自动处理几百甚至上千个并行操作,同时大幅降低了脚本的复杂性。
——————————————————————————————————
Python多进程并发(multiprocessing)
受限于Python的设计(此处指常用的CPython解释器),程序最多只能充分利用1个CPU核心。
Python提供了功能强大的多进程包multiprocessing,用户只需定义一个函数,Python便会自动处理其余所有工作。借助该包,可以轻松实现从单进程到并发执行的转换。
1、新建单一进程
若需新建少量进程,可采用如下方式:
import multiprocessing
import time
def func(msg):
for i in xrange(3):
print msg
time.sleep(1)
if __name__ == "__main__":
p = multiprocessing.Process(target=func, args=("hello", ))</
p.start()
p.join()
print "Sub-process done."
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,并需要关注结果
更多时候,我们不仅需要多进程执行,还需要关注每个进程的执行结果,代码如下:
import multiprocessing import time def func(msg): for i in xrange(3): print msg time.sleep(1) return "done " + msg if __name__ == "__main__": pool = multiprocessing.Pool(processes=4) result = [] for i in xrange(10): msg = "hello %d" %(i) result.append(pool.apply_async(func, (msg, ))) pool.close() pool.join() for res in result: print res.get() print "Sub-process(es) done."
2014.12.25更新
根据网友反馈,在Windows系统下运行可能会发生崩溃(开启大量新窗口和进程),可通过以下调用解决:
multiprocessing.freeze_support()
简易worker multiprocessing.Pool
多任务模型设计逻辑较为复杂,但Python提供了多种便捷的多任务处理类库,无需过多纠结进程或线程间的操作细节。例如multiprocessing.Pool便是其中之一。
官方提供的范例也非常简洁。
from multiprocessing import Pool def f(x): return x*x if __name__ == '__main__': pool = Pool(processes=4) # start 4 worker processes result = pool.apply_async(f, [10]) # evaluate "f(10)" asynchronously print result.get(timeout=1) # prints "100" unless your computer is *very* slow print pool.map(f, range(10)) # prints "[0, 1, 4,..., 81]"
官方范例并未做过多详细解释。恰好我手头有一段代码,需要请求数百个URL并解析HTML页面以获取信息,单线程for循环效率极低,因此注意到该模块并尝试实现多任务分析,参考代码如下:
from multiprocessing import Pool def analyse_url(url): #do something with this url return analysis_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的实例即为全部内容,希望能为大家提供参考,也希望大家多多支持本站。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













