进程间通信-Queue和进程池Pool
1.Queue的使用
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);
Queue.qsize():返回当前队列包含的消息数量;
Queue.empty():如果队列为空,返回True,反之False ;
Queue.full():如果队列满了,返回True,反之False;
Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读
到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出"Queue.Empty"异常;
2)如果block值为False,消息列队如果为空,则会立刻抛出"Queue.Empty"异常;
Queue.get_nowait():相当Queue.get(False);
Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True;
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),
直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出"Queue.Full"异常;
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出"Queue.Full"异常;
Queue.put_nowait(item):相当Queue.put(item, False);
1 import multiprocessing
2
3
4 def down_from_web(q):
5 '''模拟从网上下载数据'''
6 # 模拟从网上下载数据
7 data = [11, 22, 33, 44]
8
9 # 向列队中写入数据
10 for temp in data:
11 q.put(temp)
12
13 print('下载器已经下载完啦并且存入到列队中')
14
15
16 def analysis_data(q):
17 '''数据处理'''
18 waitting_analysis = list()
19 # 从列队中获取数据
20 while True:
21 data = q.get()
22 waitting_analysis.append(data)
23 if q.empty():
24 break
25
26 print(waitting_analysis)
27
28 def main():
29 # 1.创建一个列队
30 q = multiprocessing.Queue()
31
32 # 2.创建多个进程,将队列的引用当作实参进行传递到里面
33 p1 = multiprocessing.Process(target=down_from_web, args=(q,))
34 p2 = multiprocessing.Process(target=analysis_data, args=(q,))
35 p1.start()
36 p2.start()
37
38
39 if __name__ == '__main__':
40 main()
2.进程池
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手
动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。初始化Pool时,可以指定一个最大进程数,当有
新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么
该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务,
multiprocessing.Pool常用函数解析:
apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),
args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
close():关闭Pool,使其不再接受新的任务;
terminate():不管任务是否完成,立即终止;
join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
1 # -*- coding:utf-8 -*-
2 from multiprocessing import Pool
3 import os, time, random
4
5
6 def worker(msg):
7 t_start = time.time()
8 print("%s开始执行,进程号为%d" % (msg, os.getpid()))
9 # random.random()随机生成0~1之间的浮点数
10 time.sleep(random.random() * 2)
11 t_stop = time.time()
12 print(msg, "执行完毕,耗时%0.2f" % (t_stop - t_start))
13
14
15 if __name__ == '__main__':
16 po = Pool(3) # 定义一个进程池,最大进程数3
17 for i in range(0, 10):
18 # Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
19 # 每次循环将会用空闲出来的子进程去调用目标
20 po.apply_async(worker, (i,))
21
22 print("----start----")
23 po.close() # 关闭进程池,关闭后po不再接收新的请求
24 po.join() # 等待po中所有子进程执行完成,必须放在close语句之后
25 print("-----end-----")
3.进程池的Queue
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:
RuntimeError: Queue objects should only be shared between processes through inheritance.
下面的实例演示了进程池中的进程如何通信:
1 # -*- coding:utf-8 -*-
2
3 # 修改import中的Queue为Manager
4 from multiprocessing import Manager, Pool
5 import os, time, random
6
7
8 def reader(q):
9 print("reader启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
10 for i in range(q.qsize()):
11 print("reader从Queue获取到消息:%s" % q.get(True))
12
13
14 def writer(q):
15 print("writer启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
16 for i in "itcast":
17 q.put(i)
18
19
20 if __name__ == "__main__":
21 print("(%s) start" % os.getpid())
22 q = Manager().Queue() # 使用Manager中的Queue
23 po = Pool()
24 po.apply_async(writer, (q,))
25
26 time.sleep(1) # 先让上面的任务向Queue存入数据,然后再让下面的任务开始从中取数据
27
28 po.apply_async(reader, (q,))
29 po.close()
30 po.join()
31 print("(%s) End" % os.getpid())
作者:Ambitious
-------------------------------------------
个性签名:独学而无友,则孤陋而寡闻。做一个灵魂有趣的人!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏一分行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!