当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
1、创建进程池
例:创建进程池
创建进程池时,需要导入multiprocessing模块中的Pool类
如上图所示,我们利用Pool()类创建了一个容量为3的进程池,并且利用apply_saync()方法向进程池中添加了10次任务,该方法第一个参数接收一个函数名,进程池中的进程会执行这个函数中的程序,第二个参数是一个元组类型,表示调用的函数的参数。但是此时,程序并不会运行,因为当前状态下,向进程池添加了任务后,主程序就退出了,主程序不会等待所有进程结束就会自动结束。因此需要调用进程池的其他方法。
调用close()方法,关闭进程池,关闭后po不再接收新的请求。
调用join()方法,等待pool中所有子进程执行完成,必须放在close语句之后
当向进程池添加的任务多于进程池初始化的进程数时,不会导致堵塞,多余的任务会排队等待,直到有空闲进程去执行这个任务
multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
2、进程间通信
虽然可以利用Process()、Pool()创建不同数量进程,但是进程之间都是相互独立的。要想做到进程之间互相通信,就需要借助第三方,我们利用Queue类作为进程之间通信的媒介。
例:Queue的基本使用
队列(queue)特点是先进先出(First in First out)。在队列中涉及到这样的几个操作:入队(把数据添加到队尾)、出队(从队首取出一个数据)、队列初始化(创建一个队列)、销毁一个队列(把整个队列的数据从内存中删除)、判断队列是否为空、判断队列是否满、获取队列的长度。
队列对象的方法:
Queue.qsize() :返回queue的近似值。注意:qsize>0 不保证(get)取元素不阻塞。qsize< maxsize不保证(put)存元素不会阻塞
Queue.empty():判断队列是否为空。和上面一样注意
Queue.full():判断是否满了。和上面一样注意
Queue.put(item,block=True,timeout=None): 往队列里放数据。如果满了的话,blocking = False 直接报 Full异常。如果blocking = True,就是等一会,timeout必须为 0 或正数。None为一直等下去,0为不等,正数n为等待n秒还不能存入,报Full异常。
Queue.put_nowait(item):往队列里存放元素,不等待
Queue.get(item,block=True,timeout=None): 从队列里取数据。如果为空的话,blocking = False 直接报 empty异常。如果blocking = True,就是等一会,timeout必须为 0 或正数。None为一直等下去,0为不等,正数n为等待n秒还不能读取,报empty异常。
Queue.get_nowait(item):从队列里取元素,不等待
例:利用Queue实现进程间通信
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:
RuntimeError: Queue objects should only be shared between processes through inheritance.
例:进程池使用Queue进行通信