apply(): 首先主进程开始,碰到子进程就执行,等到子进程都执行完毕后切换到主进程,和单进程串行执行无区别
apply_async():异步非阻塞,不用等待当前进程执行完毕,随时根据系统调度进行进程切换。即便碰到主进程,子进程仍可以先运行。
import time from multiprocessing import Pool def run(count): print(“子进程编号:%s” % count) time.sleep(2) print(“子进程%s结束” % count) if __name__ == “__main__”: print(“开始执行主进程”) start_time = time.time() # 使用进程池创建子进程 pool = Pool(4) print(“开始执行子进程”) for i in range(4): pool.apply_async(run, (i, )) print(“主进程结束,总耗时%s” % (time.time() – start_time))
现在是抢占式切换,首先运行的是主进程,主进程一下子就运行完了,子进程都没有机会切换。
若想子进程执行结束完毕后再运行主进程剩余部分,则在恰当位置加上一句”sub_process_name.join()”
import time from multiprocessing import Pool def run(count): print(“子进程编号:%s” % count) time.sleep(2) print(“子进程%s结束” % count) if __name__ == “__main__”: print(“开始执行主进程”) start_time = time.time() # 使用进程池创建子进程 pool = Pool(4) print(“开始执行子进程”) for i in range(4): pool.apply_async(run, (i, )) pool.close() # 进程池调用close()后,会把进程池切换成不可再插入之状态 # close必须在join之前 pool.join() # join()调用后主进程必须等子进程全部运行结束后才接着运行 print(“主进程结束,总耗时%s” % (time.time() – start_time))
类函数获取进程池对象之后,就可以在用pool.apply_async(func…)在类函数里面执行,这个pool要与主进程的命名一致
pool.join()防止主进程在worker结束前结束
pool.close()等待进程池中的worker执行结束后再关闭
Test Env: Ubuntu16
一般的面向过程编程如果要采用进程池,只需要在主程序入口初始化进程池,然后可以在函数里分配任务队列。但是在面向对象编程中,如果直接采用这种方式去给类里面的函数分配任务,就会出错。这是因为:
pool方法都是用queue.Queue将task传递给工作进程,multiprocessing必须将数据序列化才能在进程间传递。即类中的方法因为被“包装”过一层,不能被序列化了。
可以采用类似全局变量的思路突破这层包装,使得类里面的方法能够感知到主程序的pool对象,例子如下:
from multiprocessing import Pool from time import sleep import sys from test import Tester if __name__ == “__main__”: pool = Pool(5) test1 = Tester() test1.work() test2 = Tester() test2.work() test3 = Tester() test3.work() test4 = Tester() test4.work() test5 = Tester() test5.work() test6 = Tester() test6.work() pool.close() pool.join()
# test.py import sys
import os from time import sleep class Tester: def f(self, x): for i in range(5): print(“%s---%s---%s” % (i, x, os.getpid())) sleep(1) def getPoolObject(self):
# pool's name is defined in main() return sys.modules[“__mp_main__”].pool def work(self): pool = self.getPoolObject() pool.apply_async(self.f, (5, ))
输出
实际的例子: