进程池Pool中的apply方法与apply_async的区别
apply方法是阻塞的。
意思就是等待当前子进程执行完毕后,在执行下一个进程。
例如:
import multiprocessing
#from multiprocessing import Pool
import time
def sqy(msg):
print('msg:%s' % msg)
time.sleep(3)
print('end')
if __name__=='__main__':
print('开始执行主程序')
start_time=time.time()
#使用线程池建立三个子进程
pool=multiprocessing.Pool(3)
print('开始执行三个子进程')
for i in range(3):
pool.apply(sqy,[i])
print('主进程结束 耗时 %s' %(time.time()-start_time))
结果为:
开始执行主程序
开始执行三个子进程
msg:0
end
msg:1
end
msg:2
end
主进程结束 耗时 9.788559675216675
因为apply是阻塞的,所以进入子进程执行后,等待当前子进程执行完毕,在继续执行下一个进程。
例如:
有三个进程0,1,2。等待子进程0执行完毕后,在执行子进程1,然后子进程2,最后回到主进程执行主进程剩余部分,就像上面的执行结果一样。
相当于:
for i in range(3):
p=multiprocessing.Process(target=sqy,args=(i,))
p.start()
p.join()
这样好像跟单进程串行执行没什么区别了。
2.apply_async 是异步非阻塞的。
意思就是:不用等待当前进程执行完毕,随时根据系统调度来进行进程切换。
例如:
import multiprocessing
from multiprocessing import Pool
import time
def sqy(msg):
print('msg:%s' % msg)
time.sleep(3)
print('end')
if __name__=='__main__':
print('开始执行主程序')
start_time=time.time()
#使用线程池建立三个子进程
pool=multiprocessing.Pool(3)
print('开始执行三个子进程')
for i in range(3):
#pool.apply(sqy,[i])
pool.apply_async(sqy,[i])
print('主进程结束 耗时 %s' %(time.time()-start_time))
执行结果如下:
开始执行主程序
开始执行三个子进程
主进程结束 耗时 0.1390078067779541
完全没有等待子进程执行完毕,主进程就已经执行完毕,并退出程序。
为什么会这样呢?
因为进程的切换是操作系统来控制的,抢占式的切换模式。
我们首先运行的是主进程,cpu运行很快啊,这短短的几行代码,完全没有给操作系统进程切换的机会,主进程就运行完毕了,整个程序结束。子进程完全没有机会切换到程序就已经结束了。
apply是阻塞式的。
首先主进程开始运行,碰到子进程,操作系统切换到子进程,等待子进程运行结束后,在切换到另外一个子进程,直到所有子进程运行完毕。然后在切换到主进程,运行剩余的部分。
apply_async是异步非阻塞式的。
首先主进程开始运行,碰到子进程后,主进程说:让我先运行个够,等到操作系统进行进程切换的时候,在交给子进程运行。因为我们的程序太短,然而还没等到操作系统进行进程切换,主进程就运行完毕了。
想要子进程执行,就告诉主进程:你等着所有子进程执行完毕后,在运行剩余部分。
import multiprocessing
from multiprocessing import Pool
import time
def sqy(msg):
print('msg:%s' % msg)
time.sleep(3)
print('end')
if __name__=='__main__':
print('开始执行主程序')
start_time=time.time()
#使用线程池建立三个子进程
pool=multiprocessing.Pool(3)
print('开始执行三个子进程')
for i in range(3):
#pool.apply(sqy,[i])
pool.apply_async(sqy,[i])
pool.close()
pool.join()
print('主进程结束 耗时 %s' %(time.time()-start_time))
pool.close() pool.join() 部分是及时我们要告诉主进程,你等着所有子进程运行完毕后再运行剩余部分。
注意:close必须在join前调用。
运行结果如下:
开始执行主程序
开始执行三个子进程
msg:0
msg:1
msg:2
end
end
end
主进程结束 耗时 4.188239336013794
你看,因为apply_async是异步非阻塞式,不用等待当前进程执行完毕,随时跟进操作系统调度来进行进程切换。
进程0没有执行完,就切换到进程1开始执行,进程1没有执行完,就切换到进程2,然后在切换回去。等待所有子进程运行完毕后,最后切换回主进程,执行剩余部分。
异步非阻塞式:
总耗时:3秒多。我们每个子进程休眠3秒,正因为是异步非阻塞式的,不用等待当前运行的子进程执行完毕,随时根据系统调度来进行进程切换。基本上主进程和三个子进程,四个进程是同时运行的。
阻塞式:
总耗时:9秒多。以为是阻塞式,需要等待当前子进程执行完毕后,在执行下一个子进程。每个子进程休眠3秒,三个子进程休眠9秒。基本上主进程加上子进程,四个进程就相当于在单进程中串行执行的。
python官方建议:废弃apply,使用apply_async。