WELCOME

不积跬步,无以至千里;不积小流,无以成江海。

进程间通信-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())

 

posted @ 2022-04-18 22:03  Ambitious~  阅读(115)  评论(0)    收藏  举报