day9-队列queue和生产者消费者模型
概述
队列在线程编程时特别有用,因为信息必须在多个线程之间安全地交换。
优先队列的构造函数。 maxsize是一个整数,用于设置可放入队列的项目数的上限。 一旦达到此大小,插入将会阻塞,直到队列项被消耗。 如果maxsize小于或等于零,队列大小是无限的。
首先检索最小值的条目(最低值条目是由排序的(列表条目))[0]返回的条目。 一个典型的条目模式是以下形式的元组:(priority_number,data)。
队列的重要作用
- 提高双方的运行效率,你只需要把数据放到队列中,中间可以去做别的事情。
- 完成了程序的解耦性,把紧密的联系变成松散的,客户端和服务器端的扩展对双方都没有影响。
队列类型
1.class queue.
Queue
(maxsize=0)
用法:先进先出,后进后出
>>> import queue >>> q = queue.Queue() >>> q.put(1) #先放1 >>> q.put(1) #再放1 >>> q.put(2) >>> q.put(2) >>> q.get() 1 #取1 >>> q.get() 1 #再取1 >>> q.get() 2 >>> q.get() 2 >>>
2.class queue.
LifoQueue
(maxsize=0)
用法:先进后出,后进先出,last in first out
>>> import queue >>> q = queue.LifoQueue() #生成一个队列实例 #放入的顺序为1,2 >>> q.put(1) >>> q.put(2) #取出的顺序为2,1 >>> q.get() 2 >>> q.get() 1
3.class queue.
PriorityQueue
(maxsize=0)
用法:根据优先级来取数据,存储数据时可设置优先级的队列,priority_number越小,优先级越高。
>>> import queue >>> q = queue.PriorityQueue() #生成基于优先级队列的对象 >>> q.put((-1,5)) #定义数据优先级并放入队列 >>> q.put((0,2)) >>> q.put((-4,1)) >>> q.get() #按照队列数据的优先级取出数据 (-4, 1) >>> q.get() (-1, 5) >>> q.get() (0, 2) >>>
队列方法
1.queue.Queue.put(item,block=True,timeout=None)
用法:把数据插入队列中。block参数默认为True,timeout默认值是None。如果blcok为False的话,那么在put时候超过设定的maxsize的值,就会抛出full异常。如果timeout设置的话(默认为None),说明put进去的值得个数超过maxsize值,那么会在timeout几秒之后抛出full异常。
>>> import queue >>> q = queue.Queue(maxsize=1) >>> q.put(1) >>> q.put(2,block=False) #block为False时,put超过设定值不会阻塞,抛出full异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 130, in put raise Full queue.Full >>> q.put(2,timeout=2) #timeout设置超时时间后再抛出异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 141, in put raise Full queue.Full
2.queue.Queue.qsize()
用法:查看队列大小
>>> import queue >>> q = queue.Queue() >>> q.put("d1") >>> q.put("d2") >>> q.put("d3") >>> q.qsize() 3
3.queue.Queue.get(block=True,timeout=None)
用法:从队列中移除并返回一个条目。如果可选的参数block为True并且超时时间为None(默认值),直到队列条目可用才会不阻塞。如果timeout时间有数值,则会最多阻塞超时秒数,如果在该时间队列内没有可用条目,执行get则会引发Empty异常。如果block为False,如果队列中有可用条目,则会返回一个条目,否则执行get会引发Empty异常(在这种情况下超时被忽略)。
>>> import queue >>> q = queue.Queue() >>> q.put(1) >>> q.put(2) >>> q.get() 1 >>> q.get() 2 >>> q.get(block=False) #队列中没有可用条目,在获取时将block为False则直接抛出Empty异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 161, in get raise Empty queue.Empty >>> q.get(timeout=3) #设置超时时间,在队列中没有可用条目,抛出Empty异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 172, in get raise Empty queue.Empty
4.queue.Queue.put_nowait()
用法:等同于put(item,block=False)
>>> import queue >>> q = queue.Queue(maxsize=2) #设置队列最大值 >>> q.put_nowait(1) >>> q.put_nowait(1) >>> q.put_nowait(1) #当队列中的数量大于2再put时则直接抛出Full异常 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 184, in put_nowait return self.put(item, block=False) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 130, in put raise Full queue.Full #队列满了后,抛出此Full异常
5.queue.Queue.get_nowait()
用法:等同于get(block=False)
>>> import queue >>> q = queue.Queue() >>> q.put(1) >>> q.put(2) >>> q.put(3) >>> q.get() 1 >>> q.get() 2 >>> q.get() 3 >>> q.get_nowait() #等同于get(block=False) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 192, in get_nowait return self.get(block=False) File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/queue.py", line 161, in get raise Empty queue.Empty >>> q.qsize() 0
6.queue.Queue.empty()
用法:队列如果为空返回True,否则返回False
>>> import queue >>> q = queue.Queue() >>> q.put(1) >>> q.empty() False #队列不为空 >>> q.get() 1 >>> q.empty() True #队列为空
7.queue.Queue.full()
用法:队列满了,返回True,否则返回False
>>> import queue >>> q = queue.Queue(maxsize=2) >>> q.put(1) >>> q.full() False #队列没满 >>> q.put(1) >>> q.full() True #队列满了
生产者消费者模型
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
#生产者消费者模型例子 import threading import queue q = queue.Queue() def producer(name): for i in range(10): q.put("骨头 %s" % i) print("开始等待所有的骨头被取走...") q.join() print("所有的骨头被取完了...") def consumer(name): while q.qsize() > 0: print("[%s] 取到[%s]并且吃了它...." %(name, q.get())) q.task_done() # 告知这个任务执行完了 p = threading.Thread(target=producer, args=("Dick",)) c = threading.Thread(target=consumer, args=("Jacky",)) p.start() c.start() #运行输出 开始等待所有的骨头被取走... [Jacky] 取到[骨头 0]并且吃了它.... [Jacky] 取到[骨头 1]并且吃了它.... [Jacky] 取到[骨头 2]并且吃了它.... [Jacky] 取到[骨头 3]并且吃了它.... [Jacky] 取到[骨头 4]并且吃了它.... [Jacky] 取到[骨头 5]并且吃了它.... [Jacky] 取到[骨头 6]并且吃了它.... [Jacky] 取到[骨头 7]并且吃了它.... [Jacky] 取到[骨头 8]并且吃了它.... [Jacky] 取到[骨头 9]并且吃了它.... 所有的骨头被取完了...
解析:消费者取到了生产者生产的骨头,但是看不到一个协作的过程,如生产者检测到没有骨头了再生产,而消费者一直在吃骨头
#边生产边消费例子 import threading,time import queue q = queue.Queue(maxsize=10) def producer(name): count = 1 while True: q.put("骨头 %s" % count) print("生产了骨头",count) count +=1 time.sleep(2) def consumer(name): while True: print("[%s] 取到[%s]并且吃了它...." %(name, q.get())) time.sleep(1) p = threading.Thread(target=producer, args=("Dick",)) c = threading.Thread(target=consumer, args=("Jacky",)) c1 = threading.Thread(target=consumer, args=("Sophie",)) p.start() c.start() c1.start() #运行输出 生产了骨头 1 [Jacky] 取到[骨头 1]并且吃了它.... 生产了骨头 2 [Sophie] 取到[骨头 2]并且吃了它.... 生产了骨头 3 [Jacky] 取到[骨头 3]并且吃了它.... 生产了骨头 4 [Sophie] 取到[骨头 4]并且吃了它.... 生产了骨头 5 [Jacky] 取到[骨头 5]并且吃了它.... 生产了骨头 6 [Sophie] 取到[骨头 6]并且吃了它.... 生产了骨头 7 [Jacky] 取到[骨头 7]并且吃了它.... 生产了骨头 8 [Sophie] 取到[骨头 8]并且吃了它.... 生产了骨头 9 [Jacky] 取到[骨头 9]并且吃了它.... 生产了骨头 10 [Sophie] 取到[骨头 10]并且吃了它.... 生产了骨头 11 [Jacky] 取到[骨头 11]并且吃了它.... 生产了骨头 12 [Sophie] 取到[骨头 12]并且吃了它....