在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。多进程是实现并发的手段之一,需要注意的问题是:
1.很明显需要并发执行的任务通常要远大于核数
2.一个操作系统不可能无限开启进程,通常有几个核就开几个进程
3.进程开启过多,效率反而会下降(开启进程是需要占用系统资源的,而且开启多余核数目的进程也无法做到并行)
例如当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个。。。手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
我们就可以通过维护一个进程池来控制进程数目,比如httpd的进程模式,规定最小进程数和最大进程数...
1.很明显需要并发执行的任务通常要远大于核数
2.一个操作系统不可能无限开启进程,通常有几个核就开几个进程
3.进程开启过多,效率反而会下降(开启进程是需要占用系统资源的,而且开启多余核数目的进程也无法做到并行)
例如当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个。。。手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。
我们就可以通过维护一个进程池来控制进程数目,比如httpd的进程模式,规定最小进程数和最大进程数...
ps:对于远程过程调用的高级应用程序而言,应该使用进程池,Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,就重用进程池中的进程。
import multiprocessing,time
def foo(num):
print(num)
time.sleep(1)
return num+1
if __name__ == '__main__':
pool=multiprocessing.Pool(processes=5)#令进程池执行的最大进程数为5,维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
res_l=[]
for i in range(50):
#res=pool.apply(func=foo,args=(i,))#apply方法是同步的,它会在执行完一个函数立即得到return结果(没有get方法),然后才会执行下一个,类似于串行
res=pool.apply_async(func=foo,args=(i,))#apply_async是异步的,不会立即得到return结果,而是ApplyResult类的实例,需要用get()函数获取结果
res_l.append(res)
pool.close() #关闭进程池,防止进一步操作关闭进程池,防止进一步操作
pool.join() #等待所有工作进程退出。此方法只能在close()或teminate()之后调用
#使用异步apply_async如果没有后面的join,或get,则程序整体结束,进程池中的任务还没来得及全部执行完也都跟着主进程一起结束了
for res in res_l:
print('-->',res) #apply得到的是return值,apply_async得到的是applyresult的实例
for res in res_l:
print('-->',res.get()) #只有apply_async才有get方法,得到return值
print('end...')
回调函数
需要回调函数的场景:进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数
import multiprocessing,time,os
def foo(num):
print(num)
time.sleep(1)
return num+1,os.getpid()
def bar(res):
print('bar pid is %s'%(os.getpid()))
print('%s result is %s'%(res[1],res[0]))
if __name__ == '__main__':
pool=multiprocessing.Pool(processes=5)
res_l=[]
for i in range(50):
#res=pool.apply(func=foo,args=(i,))
res=pool.apply_async(func=foo,args=(i,),callback=bar)#callback回调函数,在进程池中的一个任务执行完后,主程序会调用回调函数对任务的返回值进行处理
res_l.append(res) #callback函数是由主程序调用的,可以由pid看出
pool.close()
pool.join()
print(os.getpid())