概念
队列也是一种数据结构,和列表有点像,但是内置了锁。队列用于多线程编程时线程间的通讯,能保证线程安全。
创建
import queue
q = queue.Queue(maxsize)
括号内可以指定队列长度,默认是无限长度。
这样就创建了一个FIFO先进先出队列,它是单向的,左边放,右边取。
方法
- q.put(item, block=True, timeout=None) 往队列内放入元素item,默认是阻塞模式,线程会一直阻塞到队列中有空间为止。可以指定超时时间。如果指定block=False,队列满时放元素会报错。
- q.get(block=True, timeout=None) 从队列中取出一个元素,默认是阻塞模式,线程会一直阻塞到队列中有元素为止。如果指定block=False,队列为空时取元素会报错。
- q.qsize() 返回队列的大小
- q.empty() 返回bool值
- q.full() 返回bool值
- q.get_nowait() ===> q.get(block=False)
- q.put_nowait() ===> q.put(block=False)
- q.join() (Blocks until all items in the Queue have been gotten and processed) 生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
- q.task_done() 使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
If a join() is currently blocking, it will resume when all items have been processed (meaning that a task_done() call was received for every item that had been put() into the queue)
import queue
q = queue.Queue(5)
q.put('a')
q.put('b')
print(q.get()) # 取出一个元素,每取出一个元素都要发送task_done()信号
q.task_done()
print(q.get())
q.task_done() # 如果这一行注释掉,那么jion()会阻塞,下面也就不会打印
q.join()
print('ending')
生产者消费者模式
在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。
为什么要使用生产者和消费者模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。
什么是生产者消费者模式
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
基于队列实现生产者消费者模式:
import queue
import threading
import time, random
def producer(seq):
for item in seq:
time.sleep(random.random())
q.put(item)
print('生产者生产了:',item)
q.put(None)
def consumer():
while True:
time.sleep(random.randint(2,3))
res = q.get()
if res is None:break
print('消费者消费了:',res)
if __name__ == '__main__': # windows下,统一把进程线程写到if __name__ == '__main__':内,不会报错
q = queue.Queue()
seq = ('包子%s'%i for i in range(10))
pro = threading.Thread(target=producer, args=(seq,)) # 生产者线程,可以在主进程,也可以开多个
con = threading.Thread(target=consumer) # 消费者线程,可以开多个
pro.start()
con.start()
pro.join()
con.join()
print('完成了生产消费')
对列的其它模式
后进先出/先进后出
q= queue.LifoQueue()
import queue
q = queue.LifoQueue()
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())
'''
3
2
1'''
优先级
q = queue.PriorityQueue()
Variant of Queue that retrieves open entries in priority order (lowest first).Entries are typically tuples of the form: (priority number, data).
import queue
q = queue.PriorityQueue()
q.put('hello')
q.put('world')
q.put('bbc')
print(q.get())
print(q.get())
print(q.get())
'''由低到高取
bbc
hello
world
'''