Python 3 并发编程多进程之队列(推荐使用)

进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的。

可以往队列里放任意类型的数据

创建队列的类(底层就是以管道和锁定的方式实现):

  1. 1 Queue([maxsize]):创建共享的进程队列,Queue是多进程安全的队列,可以使用Queue实现多进程之间的数据传递。

参数介绍:

  1. 1 maxsize是队列中允许最大项数,省略则无大小限制。

方法介绍:

1、主要方法:

  1. q.put方法用以插入数据到队列中,put方法还有两个可选参数:blockedtimeout。如果blockedTrue(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blockedFalse,但该Queue已满,会立即抛出Queue.Full异常。
  2. q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blockedtimeout。如果blockedTrue(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blockedFalse,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
  3. q.get_nowait():同q.get(False)
  4. q.put_nowait():同q.put(False)
  5. q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
  6. q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
  7. q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样

2、其他方法(了解):

  1. 1 q.cancel_join_thread():不会在进程退出时自动连接后台线程。可以防止join_thread()方法阻塞
  2. 2 q.close():关闭队列,防止队列中加入更多数据。调用此方法,后台线程将继续写入那些已经入队列但尚未写入的数据,但将在此方法完成时马上关闭。如果q被垃圾收集,将调用此方法。关闭队列不会在队列使用者中产生任何类型的数据结束信号或异常。例如,如果某个使用者正在被阻塞在get()操作上,关闭生产者中的队列不会导致get()方法返回错误。
  3. 3 q.join_thread():连接队列的后台线程。此方法用于在调用q.close()方法之后,等待所有队列项被消耗。默认情况下,此方法由不是q的原始创建者的所有进程调用。调用q.cancel_join_thread方法可以禁止这种行为

3、应用:

  1. '''
  2. multiprocessing模块支持进程间通信的两种主要形式:管道和队列
  3. 都是基于消息传递实现的,但是队列接口
  4. 1:可以往队列里放任意类型的数据 2 队列:先进先出
  5. '''
  6.  
  7. from multiprocessing import Process,Queue
  8. import time
  9. q=Queue(3)
  10.  
  11. #put ,get ,put_nowait,get_nowait,full,empty
  12. q.put(3)
  13. q.put(3)
  14. q.put(3)
  15. print(q.full()) #满了
  16.  
  17. print(q.get())
  18. print(q.get())
  19. print(q.get())
  20. print(q.empty()) #空了

4、生产者消费者模型

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

5、为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

6、什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

7、基于队列实现生产者消费者模型

  1. from multiprocessing import Process,Queue
  2. import time,random,os
  3. def consumer(q):
  4. while True:
  5. res=q.get()
  6. time.sleep(random.randint(1,3))
  7. print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))
  8.  
  9. def producer(q):
  10. for i in range(10):
  11. time.sleep(random.randint(1,3))
  12. res='包子%s' %i
  13. q.put(res)
  14. print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
  15.  
  16. if __name__ == '__main__':
  17. q=Queue()
  18. #生产者们:即厨师们
  19. p1=Process(target=producer,args=(q,))
  20.  
  21. #消费者们:即吃货们
  22. c1=Process(target=consumer,args=(q,))
  23.  
  24. #开始
  25. p1.start()
  26. c1.start()
  27. print('主')

生产者消费者模型

此时的问题是主进程永远不会结束,原因是:生产者p在生产完后就结束了,但是消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。

解决方式无非是让生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环。

  1. from multiprocessing import Process,Queue
  2. import time,random,os
  3. def consumer(q):
  4. while True:
  5. res=q.get()
  6. if res is None:break #收到结束信号则结束
  7. time.sleep(random.randint(1,3))
  8. print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))
  9.  
  10. def producer(q):
  11. for i in range(10):
  12. time.sleep(random.randint(1,3))
  13. res='包子%s' %i
  14. q.put(res)
  15. print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
  16. q.put(None) #发送结束信号
  17. if __name__ == '__main__':
  18. q=Queue()
  19. #生产者们:即厨师们
  20. p1=Process(target=producer,args=(q,))
  21.  
  22. #消费者们:即吃货们
  23. c1=Process(target=consumer,args=(q,))
  24.  
  25. #开始
  26. p1.start()
  27. c1.start()
  28. print('主')

生产者在生产完毕后发送结束信号None

注意:结束信号None,不一定要由生产者发,主进程里同样可以发,但主进程需要等生产者结束后才应该发送该信号。

  1. from multiprocessing import Process,Queue
  2. import time,random,os
  3. def consumer(q):
  4. while True:
  5. res=q.get()
  6. if res is None:break #收到结束信号则结束
  7. time.sleep(random.randint(1,3))
  8. print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))
  9.  
  10. def producer(name,q):
  11. for i in range(2):
  12. time.sleep(random.randint(1,3))
  13. res='%s%s' %(name,i)
  14. q.put(res)
  15. print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
  16.  
  17. if __name__ == '__main__':
  18. q=Queue()
  19. #生产者们:即厨师们
  20. p1=Process(target=producer,args=('包子',q))
  21. p2=Process(target=producer,args=('骨头',q))
  22. p3=Process(target=producer,args=('泔水',q))
  23.  
  24. #消费者们:即吃货们
  25. c1=Process(target=consumer,args=(q,))
  26. c2=Process(target=consumer,args=(q,))
  27.  
  28. #开始
  29. p1.start()
  30. p2.start()
  31. p3.start()
  32. c1.start()
  33.  
  34. p1.join() #必须保证生产者全部生产完毕,才应该发送结束信号
  35. p2.join()
  36. p3.join()
  37. q.put(None) #有几个生产者就应该发送几次结束信号None
  38. q.put(None) #发送结束信号
  39. q.put(None) #发送结束信号
  40. print('主')

主进程在生产者生产完毕后发送结束信号None

其实我们的思路无非是发送结束信号而已,有另外一种队列提供了这种机制

  1. #JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。
  2. #参数介绍:
  3. maxsize是队列中允许最大项数,省略则无大小限制。
  4. #方法介绍:
  5. JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
  6. q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
  7. q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
  1. from multiprocessing import Process,JoinableQueue
  2. import time,random,os
  3. def consumer(q):
  4. while True:
  5. res=q.get()
  6. time.sleep(random.randint(1,3))
  7. print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))
  8.  
  9. q.task_done() #向q.join()发送一次信号,证明一个数据已经被取走了
  10.  
  11. def producer(name,q):
  12. for i in range(10):
  13. time.sleep(random.randint(1,3))
  14. res='%s%s' %(name,i)
  15. q.put(res)
  16. print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
  17. q.join()
  18.  
  19. if __name__ == '__main__':
  20. q=JoinableQueue()
  21. #生产者们:即厨师们
  22. p1=Process(target=producer,args=('包子',q))
  23. p2=Process(target=producer,args=('骨头',q))
  24. p3=Process(target=producer,args=('泔水',q))
  25.  
  26. #消费者们:即吃货们
  27. c1=Process(target=consumer,args=(q,))
  28. c2=Process(target=consumer,args=(q,))
  29. c1.daemon=True
  30. c2.daemon=True
  31.  
  32. #开始
  33. p_l=[p1,p2,p3,c1,c2]
  34. for p in p_l:
  35. p.start()
  36.  
  37. p1.join()
  38. p2.join()
  39. p3.join()
  40. print('主')
  41.  
  42. #主进程等--->p1,p2,p3等---->c1,c2
  43. #p1,p2,p3结束了,证明c1,c2肯定全都收完了p1,p2,p3发到队列的数据
  44. #因而c1,c2也没有存在的价值了,应该随着主进程的结束而结束,所以设置成守护进程

Python 3 并发编程多进程之队列(推荐使用)的更多相关文章

  1. Python 3 并发编程多进程之进程同步(锁)

    Python 3 并发编程多进程之进程同步(锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,竞争带来的结果就是错乱,如何控制,就是加锁处理. 1. ...

  2. Python 3 并发编程多进程之守护进程

    Python 3 并发编程多进程之守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemo ...

  3. Python之并发编程-多进程

    目录 一.multiprocessiong模块介绍 二.Process类的介绍 三.进一步介绍(守护进程.锁.队列.管道.事件等) 1.守护进程 2.锁(同步锁.互斥锁) 3.信号量(了解) 4.队列 ...

  4. Python 3 并发编程多进程之进程池与回调函数

    Python 3 进程池与回调函数 一.进程池 在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间.多进程是实现并发的手段之一,需要注意 ...

  5. Python 3 并发编程多进程之进程与线程

    Python 3 进程与线程 进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的 ...

  6. python 3 并发编程多进程 paramiko 模块

    python 3 paramiko模块 paramiko是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,值得一说的是,fabric和ansible内部的远程管理就是使用的pa ...

  7. python 并发编程 多进程 队列目录

    python 并发编程 多进程 队列 python 并发编程 多进程 生产者消费者模型介绍 python 并发编程 多进程 生产者消费者模型总结 python 并发编程 多进程 JoinableQue ...

  8. python并发编程&多进程(二)

    前导理论知识见:python并发编程&多进程(一) 一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_cou ...

  9. Python并发编程-多进程

    Python并发编程-多进程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.多进程相关概念 由于Python的GIL全局解释器锁存在,多线程未必是CPU密集型程序的好的选择. ...

随机推荐

  1. SQL中拆分字符串substr及统计字符出现频数replace用法实例讲解

    一.拆分字符串为若干行 例一:要求将表emp中的'king'按照每行一个单词拆成四行 注意:substr(str,pos):截取pos位置开始的字符: substr(str,pos,len):从pos ...

  2. handlebars.js基础学习笔记

    最近在帮学校做个课程网站,就有人推荐用jquery+ajax+handlebars做网站前端,刚接触发现挺高大上的,于是就把一些基础学习笔记记录下来啦. 1.引用文件: jquery.js文件下载:h ...

  3. Mac 下Versions的 svn无法上传 .a 文件的问题

    Xcode自带的svn和Versions以及一些其它工具都默认ignore".a"文件. 解决办法有两个: 方法一:使用命令行添加文件([转]原文在这) 1.打开终端,输入cd,空 ...

  4. IQueryable和IEnumerable以及AsEnumerable()和ToList()的区别

    注意:本文背景为 Linq to sql .文中ie指代IEnumerable,iq指代IQueryable. IQueryable 和 IEnumerable 的区别 IQueryable 延时执行 ...

  5. layer 不居中的坑爹问题

    使用了该代码弹出一个图片.但居然不居中 var layer_index = layer.open({ type: 1, title: false, closeBtn: 0, area: '516px' ...

  6. Python基础(字符编码与文件处理)

    一.了解字符编码的知识储备 1.计算机基础知识(三副图) 2.文本编辑器存取文件的原理(notepad++,Pycharm,word) 打开编辑器就启动了一个进程,是在内存中运行的,所以在编辑器写的内 ...

  7. AccessibilityService 官网介绍

    AccessibilityService extends Service java.lang.Object    ↳ android.content.Context      ↳ android.co ...

  8. 《HBase in Action》 第二章节的学习总结 ---- HBase基本组成

    准备工作:采用的HBase版本是:CDH4.5,其中的Hadoop版本是:hadoop-2.0.0-cdh4.5.0:HBase版本是:hbase-0.94.6-cdh4.5.0: Hbase的配置文 ...

  9. Python调用API接口的几种方式 数据库 脚本

    Python调用API接口的几种方式 2018-01-08 gaoeb97nd... 转自 one_day_day... 修改 微信分享: 相信做过自动化运维的同学都用过API接口来完成某些动作.AP ...

  10. Agri-Net - poj 1258 (Prim 算法)

      Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 44373   Accepted: 18127 Description F ...