4.线程
1.语法
2.join
3.线程锁之Lock\Rlock\信号量
4.将线程变为守护进程
5.Event事件 
* 6.queue队列
* 7.生产者消费者模型 4.6 queue队列 queue非常有用,当信息必须安全的在多个线程之间进行数据交换的时候就应该想到queue
所以,queue它能保证数据被安全的在多个线程之间进行交换,那他就是天生的线程安全.
queue有那么几种:
class queue.Queue(maxsize=0) # 先入先出
class queue.LifoQueue(maxsize=0) # last in fist out 后进先出
class queue.PriorityQueue(maxsize=0) # 存储数据时可以设置优先级的队列,如果你实例化一个优先级队列,在往队列中put时参数就需要一个元组了,如:put((优先级数,value)),其中优先及数越小,优先级越高.
# 当然q.get()取数据时,取出来的也是元组格式.(优先级数,value) 它有几种方法:
     两个状态:
exception queue.Empty
正常情况下取一个queue,如果取完了(空了),就进入了一个阻塞状态(程序就开始等待).但是你也可以把它设置成非阻塞.
正常取的方法:queue.get() ,设置成非阻塞queue.get_nowaitt() ,如果设置了非阻塞.当队列取完了,程序就会跑出一个异常. exception queue.Full
正常情况下可以设置队列的大小,如果队列满了,也会进入一个阻塞状态.同样也可以设置非阻塞抛异常的方法.
正常存方法queue.put() , 设置成非阻塞queue.put_nowait()后如果queue满了,那么程序会抛异常.
几个常用方法:
Queue.qsize() # 获取当前的queue里的值的长度.
Queue.empty() # 判断queue是不是为空,如果为空则返回True
Queue.full() # 判断queue是不是满了,如果满了则返回True
Queue.put(item,block=True,timeout=None) # 默认是是block,这个timeout是做什么的.当block=True时,如果queue队列满了以后,程序会一直阻塞.那么有些情况下,我们想不能一直阻塞.timeout就其作用了,阻塞一段时间后,报一个"Full exception" 异常
Queue.put_nowait(item) # 直接不等了,如果队列满了则报Full exception 异常
Queue.get(block=True,timeout=None) # 默认block=True ,如果取不到数据,一直阻塞,timeout设置阻塞多久后抛 Empty exception 异常
Queue.get_nowait()
Queue.task_done() # 像是一个信号,当消费者消费完了,通知生产者已经消费完了,你要生产了.task_done()方法用于消费者线程. 4.7 生产者消费者模型
这是一个新的概念,干嘛用的?
它是用于两个独立的系统之间,一个系统用于生产消息,一个用于消费消息.它的最重要的作用,使你的程序解偶,使你两个系统之间关联性没有那么大.两个系统完全的分开了,分开了之后,两个系统之间的通信就通过生产者消费者模型这个桥梁.
消费者,生产者这是以后做开发最常用设计模式之一.
既然说生产者\消费者模型是两个系统之间的桥梁,那么他两之间怎么去通信.怎么实现生产者和消费者?
拿厨师和食客做举例:
1.厨师作为生产者,生产包子
2.食客作为消费者,吃包子.
那么问题来了:他两在什么的情况下,效率可以达到最高.
第一种情况:消费者每次跑到生产者面前说我要吃包子,然后厨师做(花1分钟),然后把包子给消费者.
如果现在又来了一个消费者.他两同时跟厨师说要吃包子,厨师的处理过程就是,先给消费者1做包子,做好后给消费者1,然后在给消费者2.
这里我们可以知道消费者2,要等待厨师做2个包子的时间.消费者2就浪费时间了.那么我们想在厨师做包子的期间,消费者2能不能去做其他事情.
目前不行,因为消费者2走后,消费者3来了.要买包子,作为生产者程序的厨师是串行的,它只能等消费者2取走包子后继续做包子3.所以这种情况下,消费者2就只能在窗口等着,哪都不能去.
那么有么有解决办法? 第二种情况:作为一名聪明的厨师,肯定能想到,我找一个保鲜盒,我先做上3个放那.当消费者1来要包子,我去保鲜盒里拿1个给它,消费者2来要包子,同样也去保鲜盒拿包子.等空下来在去做包子(目的是要保持保鲜盒中有3个包子).但问题来了?当你空下来去做包子的时候,有人来买包子.作为一名合格的厨师,你不能轻易的就把做包子的事情中断,去给食客拿包子.因为那不符合一名高尚厨师的规范.
同样,这些在厨师做包子的时间段要买包子的食客,也还是要等上一段时间.虽然比之前的情况好一些,但消费者的体验也同样不是很好. 第三种情况:为了提高消费者的体验,厨师想到了,招一个漂亮的女服务员,让服务员保存3个包子.消费者不在和厨师直接通信,消费者直接去找服务员说我要吃包子.
服务员拿一个包子给消费者1后,她就告诉厨师,我这边少一个包子,你生产一个.厨师就只和服务员通话. 消费者也只和服务员通话. 服务员只做双方信息的传递.
第三种情况就算一个生产者\消费者模型
那么用代码如何实现这个服务员呢:这就可以使用queue队列了. 用代码实现:
             #!/usr/bin/env python3.
#__author__:"ted.zhou"
'''
简单的生产者消费者模型代码
1对多
''' import threading,queue def consumer(n):
'''
简单的一个消费者
:param n:
:return:
'''
print("我是消费者 [%s]"%n)
print("consumer [%s] get task: %s"%(n,q.get()))
# q.task_done() # 通知生产者的标记 def producer(n):
for i in range():
print("厨师%s生产了编号为%s的包子!"%(n,i))
q.put(i)
# q.join() # 消费者.task_done()方法告诉的标记不为空,就一直阻塞
print("两个包子都被消费者吃掉了") q = queue.Queue(maxsize=)
c1 = threading.Thread(target=consumer,args=[,])
c2 = threading.Thread(target=consumer,args=[,])
c3 = threading.Thread(target=consumer,args=[,]) p = threading.Thread(target=producer,args=['ted',]) c1.start()
c2.start()
c3.start()
p.start()
代码实现结果:
我是消费者 []
我是消费者 []
我是消费者 []
厨师ted生产了编号为0的包子!
厨师ted生产了编号为1的包子!
两个包子都被消费者吃掉了
consumer [] get task:
consumer [] get task:
        上面的代码,我们看到线程没有结束.原因是线程c3 种q.get()还在阻塞状态.因为厨师只做了2个包子,并且两个包子通过管道已经被消费者c1.c2吃掉了.
轮到消费者c3时,已经没包子了.所以c3 中,q.get()阻塞在那了.
实际中我们肯定不是这样的.作为生产者,希望服务员能告诉生产者什么时候该做包子,
两种方式:1.厨师不停的去问服务员,你那里包子还够不够.2.服务员在没有包子的时候告诉厨师,没存货了,你赶紧做.
方式1,用代码也能实现,就是贩判断队列是否为空if q.empty(),为空则去做.但这样会有问题,因为你的程序处于不断的循环状态.不可取
方式2,作为服务员角色的队列,主动告诉生产者程序,队列是不是空了,那这就要用到队列的q.task_done()方法.返回给队列的q.join()方法队列是否为空的状态.
这样在消费者程序中每次从队列get()后,执行一次q.task_done()方法.而生产者q.join()方法一直处于阻塞状态.只有当传过来的q.task_done() 中说明队列已经为空时,生产者程序才会中断阻塞状态,继续执行下面的代码.
如此以来代码应该优化成:
             #!/usr/bin/env python3.
#__author__:"ted.zhou"
'''
简单的生产者消费者模型代码
1对多
''' import threading,queue def consumer(n):
'''
简单的一个消费者
:param n:
:return:
'''
print("我是消费者 [%s]"%n)
print("consumer [%s] get task: %s"%(n,q.get()))
q.task_done() # 通知生产者的标记 def producer(n):
count =
while True:
print("厨师%s生产了编号为%s的包子!"%(n,count))
q.put(count)
count +=
q.join() # 消费者.task_done()方法告诉的标记不为空,就一直阻塞
print("包子都被消费者吃掉了") q = queue.Queue(maxsize=)
c1 = threading.Thread(target=consumer,args=[,])
c2 = threading.Thread(target=consumer,args=[,])
c3 = threading.Thread(target=consumer,args=[,]) p = threading.Thread(target=producer,args=['ted',]) c1.start()
c2.start()
c3.start()
p.start()
        这里我们不在使用for循环,而是每次只生产1个包子.在实际的开发过程中也是这样,一个生产者一次只生产一个信息供消费者消费,而生产者消费者模型的本身就是为了代码根据实际情况随意的扩展消费者线程和生产者线程.
上面的代码实例是1对多的实例,上面的代码中生产者的代码只是打印,不消耗时间,所以感觉1对多的情况下消费者也不怎么排队,但是如果生产者代码要耗费0.5秒,每次生产包子都耗费0.5秒.那么执行程序这个感觉就是每次生产0.5秒,3个消费者就要排队了.所以我们要加一个厨师(生产者.)
代码如下:
             #!/usr/bin/env python3.
#__author__:"ted.zhou"
'''
简单的生产者消费者模型代码
1对多
''' import threading,queue
import time def consumer(n):
'''
简单的一个消费者
:param n:
:return:
'''
print("我是消费者 [%s]"%n)
print("consumer [%s] get task: %s"%(n,q.get()))
q.task_done() # 通知生产者的标记 def producer(n):
count = while True:
time.sleep(0.5) # 模拟生产耗费0.5秒
print("厨师%s生产了编号为%s的包子!"%(n,count))
q.put(count)
count +=
q.join() # 消费者.task_done()方法告诉的标记不为空,就一直阻塞
print("包子都被消费者吃掉了") q = queue.Queue(maxsize=)
c1 = threading.Thread(target=consumer,args=[,])
c2 = threading.Thread(target=consumer,args=[,])
c3 = threading.Thread(target=consumer,args=[,]) p = threading.Thread(target=producer,args=['ted',])
p2 = threading.Thread(target=producer,args=['bob',])
p3 = threading.Thread(target=producer,args=['lily',])
c1.start()
c2.start()
c3.start()
p.start()
p2.start()
p3.start()
代码执行结果如下:
我是消费者 []
我是消费者 []
我是消费者 []
厨师ted生产了编号为1的包子!
厨师bob生产了编号为1的包子!
consumer [] get task:
厨师lily生产了编号为1的包子!
consumer [] get task:
consumer [] get task:
厨师lily生产了编号为2的包子!
厨师ted生产了编号为2的包子!
厨师bob生产了编号为2的包子!
        我们看到结果 生产者都生产了第二次,那么问题来了如果此时我们的生产者有100个呢,因为q.join()方法是同时获得状态的.而队列最大是3个,就一下子多出来97个在那里阻塞着.
而当队列里的三个包子消费掉了.那三个执行到q.join()代码的生产者线程又回在生产3个.这样就会导致生产者一直处于有97个处于put()阻塞状态.这和我们写代码的程序员的想法不一致,我们想的当然是当队列为空时,先把余下的97个put()减去3个,先前执行到q.join()方法的线程不动.
那么这样实现作为一个有强迫症的程序员的想法呢.答案是,根据生产者消费者模型可以随意扩展,消费者线程数和生产者线程数的特点.选择1对1的方式.既有多少个消费者,咱就有多少生产者.(其实就是没有好的办法,指定q.task_done指通知数量)
但是如果你非要在给3个消费者建立100个生产者,也是有办法的:(思路就是在生产之前对队列做判断,且每个生产者判断之前等待的时间不一致),但是效果不好,因为熟眠时间短,效果不好,睡眠时间长影响性能.所以不建议用. 代码如下:
         #!/usr/bin/env python3.
#__author__:"ted.zhou"
'''
简单的生产者消费者模型代码
1对多
''' import threading,queue
import time
import random
def consumer(n):
'''
简单的一个消费者
:param n:
:return:
'''
print("我是消费者 [%s]"%n)
print("consumer [%s] get task: %s"%(n,q.get()))
q.task_done() # 通知生产者的标记 def producer(n):
count = while True:
time.sleep(random.random())
if q.qsize() < :
time.sleep(0.5) # 模拟生产耗费0.5秒
print("厨师%s生产了编号为%s的包子!"%(n,count))
q.put(count)
count +=
# q.join() # 消费者.task_done()方法告诉的标记不为空,就一直阻塞
# print("包子都被消费者吃掉了")
else:
q.join()
print("包子都被消费者吃掉了") q = queue.Queue(maxsize=)
c1 = threading.Thread(target=consumer,args=[,])
c2 = threading.Thread(target=consumer,args=[,])
c3 = threading.Thread(target=consumer,args=[,]) p = threading.Thread(target=producer,args=['ted',])
p2 = threading.Thread(target=producer,args=['bob',])
p3 = threading.Thread(target=producer,args=['lily',])
c1.start()
c2.start()
c3.start()
p.start()
p2.start()
p3.start()
执行结果:
我是消费者 []
我是消费者 []
我是消费者 []
厨师bob生产了编号为1的包子!
consumer [] get task:
包子都被消费者吃掉了
厨师lily生产了编号为1的包子!
consumer [] get task:
包子都被消费者吃掉了
厨师ted生产了编号为1的包子!
consumer [] get task:
包子都被消费者吃掉了
厨师lily生产了编号为2的包子!
厨师bob生产了编号为2的包子!
    总之,你觉得生产者慢就给生产者加线程,如果觉得消费者慢,就给消费者加线程
总结: 1.生产者 和 消费者 1对1 情况最佳;2.你写的生产者生产信息?所花费的时间要比消费者消费信息所花费的时间短;(因为只有这样,消费者消费完还没到下一次消费,生产者就已经把queue队列又存满了) PS:上面的例子,我们是在一个程序里弄出来多个线程模拟的.算是之前说的两个独立的系统吗?当然不算,但是表现出来的结果是一样的.
生产环境中说的两个独立的系统,那可能都不是一个语言写的,比如生产者是python,而消费者是C语言写的.这种情况下,队列就不是用python的queue模块了,那就是真正的队列了:redis,zibbitMQ,zeroMQ等真正的MQ,后面会学习zibbitMQ

python2.0_s12_day9之day8遗留知识(queue队列&生产者消费者模型)的更多相关文章

  1. #queue队列 #生产者消费者模型

    #queue队列 #生产者消费者模型 #queue队列 #有顺序的容器 #程序解耦 #提高运行效率 #class queue.Queue(maxsize=0) #先入先出 #class queue.L ...

  2. Python学习笔记——进阶篇【第九周】———线程、进程、协程篇(队列Queue和生产者消费者模型)

    Python之路,进程.线程.协程篇 本节内容 进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Ev ...

  3. python并发编程之多进程(二):互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型

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

  4. Day034--Python--锁, 信号量, 事件, 队列, 生产者消费者模型, joinableQueue

    进程同步: 1. 锁 (重点)    锁通常被用来实现对共享资源的同步访问.为每一个共享资源创建一个Lock对象,当你需要访问该资源时,调用acquire方法来获取锁对象(如果其它线程已经获得了该锁, ...

  5. python 全栈开发,Day39(进程同步控制(锁,信号量,事件),进程间通信(队列,生产者消费者模型))

    昨日内容回顾 python中启动子进程并发编程并发 :多段程序看起来是同时运行的ftp 网盘不支持并发socketserver 多进程 并发异步 两个进程 分别做不同的事情 创建新进程join :阻塞 ...

  6. 5 并发编程-(进程)-队列&生产者消费者模型

    1.队列的介绍 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的 创建队列的类(底层就是以管道和锁定的方式实现 ...

  7. python网络编程--进程(方法和通信),锁, 队列,生产者消费者模型

    1.进程 正在进行的一个过程或者说一个任务.负责执行任务的是cpu 进程(Process: 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在 ...

  8. python开发进程:互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型

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

  9. 队列&生产者消费者模型

    队列 ipc机制:进程通讯 管道:pipe 基于共享的内存空间 队列:pipe+锁 queue from multiprocessing import Process,Queue ### 案例一 q ...

随机推荐

  1. org.hibernate.HibernateException: Could not parse configuration: /hibernate.cfg.xm

    org.hibernate.HibernateException: Could not parse configuration: /hibernate.cfg.xm 检查jar包是否正确以及配置的xm ...

  2. PowerShell中实现人机交互

    编写脚本的过程中有很多时候需要进行人机交互,比如我写一个脚本,需要动态的输入一些内容,比如用户名和密码之类的东西,这些是没办法事先写进代码里的.而通过外部文件进行信息读取,友好性又差了点.所以当我们需 ...

  3. 在centos中安装mangodb

    1.下载完安装包,并解压 tgz(以下演示的是 64 位 Linux上的安装) curl -O https://fastdl.mongodb.org/linux/mongodb-linux-x86_6 ...

  4. Java并发(一)Java并发/多线程教程

    在过去一台电脑只有单个CPU,并且在同一时间只能执行单个程序.后来出现的"多任务"意味着电脑在可以同时执行多个程序(AKA任务或者进程).虽然那并不是真正意义上的"同时& ...

  5. UTF-8以字节为单位对Unicode进行编码

    UTF-8以字节为单位对Unicode进行编码.从Unicode到UTF-8的编码方式如下: Unicode编码(16进制) UTF-8 字节流(二进制) 000000 - 00007F 0xxxxx ...

  6. ubuntu多节点安装kubernetes

    在ubuntu上面多节点安装kubernetes,假设有两台机器 master:192.168.1.84 minion:192.168.1.83 You wil now need to configu ...

  7. ansible 的user模块

    user模块与group模块 user模块是请求的是useradd, userdel, usermod三个指令,goup模块请求的是groupadd, groupdel, groupmod 三个指令. ...

  8. 修改jvm内存大小

  9. Android Studion的Monitor中显示No Debuggable Application的解决方法

    在使用Android Studion的时候,突然android Monitor中无法下拉显示调试项目,只是一直提示No Debuggable Application,然后上网搜索的解决办法: 第一种方 ...

  10. 普通windows版本安装winServer的特色功能 以dedup功能为展示点

    安装 Windows 功能角色 1.选择安装源 在 Windows 8.1 系统上不存在重复数据删除功能,需要从对应的服务器版本,即 Windows Server 2012 R2 上提取相关文件. 2 ...