Queue消息队列
在python中,多个进程之间是无法共享全局变量的。但有时候我们又必须使用同一些数据。这时候就可以利用消息队列来实现。
Queue消息队列就相当于一个管道,数据从一头进,另一头出。
示例程序:
import multiprocessing
import time
# 创建消息队列,用来储存数据
q = multiprocessing.Queue()
def put_in():
for i in range(10):
q.put(i)
print(i, ' put in')
time.sleep(0.1)
def get_out():
for _ in range(10):
print(q.get(), ' get out')
pp = multiprocessing.Process(target=put_in)
gp = multiprocessing.Process(target=get_out)
pp.start()
gp.start()
运行结果:
0 put in
0 get out
1 put in
1 get out
2 put in
2 get out
3 put in
3 get out
4 put in
4 get out
5 put in
5 get out
6 put in
6 get out
7 put in
7 get out
8 put in
8 get out
9 put in
9 get out
Queue常见方法
- Queue.qsize():返回当前队列包含的消息数量;
- Queue.empty():如果队列为空,返回True,反之False ;
- Queue.full():如果队列满了,返回True,反之False;
- Queue.get():获取队列中的一条消息,然后将其从列队中移除,可传参超时时长。
- Queue.get_nowait():相当Queue.get(False),取不到值时触发异常:Empty;
- Queue.put():将一个值添加进数列,可传参超时时长。
- Queue.put_nowait():相当于Queue.get(False),当队列满了时报错:Full
其中,
Queue.empty()
方法不可靠,容易出现错误判断,与代码运行速度有关,因此可以用Queue.qsize()
来判断队列是否为空。
Pool进程池
在你需要多进程的时候,又或是你不清楚需要多少进程合适的时候。我们可以利用进程池来协助创建进程。
进程池的创建需要调用multiprocessing.Pool(5)
方法,其中括号里传递的参数是最大可创建进程数量。如果没有传参,默认无限量。
进程池创建并调用进程代码如下:
import multiprocessing
import time
# 拷贝任务
def work():
print("复制中...", multiprocessing.current_process().pid)
time.sleep(0.5)
if __name__ == '__main__':
# 创建进程池
# 3:进程池中进程的最大个数
pool = multiprocessing.Pool(3)
# 模拟大批量的任务,让进程池去执行
for i in range(5):
# 循环让进程池执行对应的work任务
# 同步执行任务,一个任务执行完成以后另外一个任务才能执行
pool.apply(work)
创建进程池后,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
另外,在执行进程时候,选择pool.apply()
方法表示的是同步进程池。而我们一般用pool.apply_async()
,这叫做异步进程池。在使用异步进程池的时候,我们应该在最后记得关闭进程池,用来告诉主进程不会再有更多的进程进来。另外还要加上进程池进程等待。让主进程等待所有进程池进程运行完之后再退出。
示例代码:
# 进程池:池子里面放的进程,进程池会根据任务执行情况自动创建进程,而且尽量少创建进程,合理利用进程池中的进程完成多任务
import multiprocessing
import time
# 拷贝任务
def work():
print("复制中...", multiprocessing.current_process().pid)
# 获取当前进程的守护状态
# 提示:使用进程池创建的进程是守护主进程的状态,默认自己通过Process创建的进程是不是守住主进程的状态
# print(multiprocessing.current_process().daemon)
time.sleep(0.5)
if __name__ == '__main__':
# 创建进程池
# 3:进程池中进程的最大个数
pool = multiprocessing.Pool(3)
# 模拟大批量的任务,让进程池去执行
for i in range(5):
# 循环让进程池执行对应的work任务
# 同步执行任务,一个任务执行完成以后另外一个任务才能执行
# pool.apply(work)
# 异步执行,任务执行不会等待,多个任务一起执行
pool.apply_async(work)
# 关闭进程池,意思告诉主进程以后不会有新的任务添加进来
pool.close()
# 主进程等待进程池执行完成以后程序再退出
pool.join()