queue模块是python官方自带模块,它实现了多生产者、多消费者队列,特别适用于在多线程间必须安全地交换消息的场合。
queue模块实现了三种类型的队列,它们都是类,区别仅仅是消息的取回顺序。使用Queue类创建的是先进先出的队列(firt in first out,FIFO),使用LifoQueue类创建的是后进先出的队列(last in first out,LIFO),使用PriorityQueue类创建的是优先级队列。这三种队列内部使用了锁来阻塞竞争线程,即多个线程只能排队轮流使用队列,不能同时并行使用队列。
下面我将详细讲述这三种队列的使用方法,讲述的顺序是先看模块的接口源码、再讲解接口说明、最后列举案例。
先进先出Queue
一、接口源码
class Queue(Generic[_T]):
maxsize: int
mutex: Lock # undocumented
not_empty: Condition # undocumented
not_full: Condition # undocumented
all_tasks_done: Condition # undocumented
unfinished_tasks: int # undocumented
queue: Any # undocumented
def __init__(self, maxsize: int = ...) -> None: ...
def _init(self, maxsize: int) -> None: ...
def empty(self) -> bool: ...
def full(self) -> bool: ...
def get(self, block: bool = ..., timeout: Optional[float] = ...) -> _T: ...
def get_nowait(self) -> _T: ...
def _get(self) -> _T: ...
def put(self, item: _T, block: bool = ..., timeout: Optional[float] = ...) -> None: ...
def put_nowait(self, item: _T) -> None: ...
def _put(self, item: _T) -> None: ...
def join(self) -> None: ...
def qsize(self) -> int: ...
def _qsize(self) -> int: ...
def task_done(self) -> None: ...
二、接口说明
三、案例,Queue中的join和task_done方法:
queue类的put和put_nowait是存消息,get和get_nowait方法是取消息,qsize、full、empty是判断消息队列,这些用法非常简单。我这里重点讲一下极其有用且少有人会用的join和taskdone方法。
以下是生产者、消费者模型的案例:
import time
import random
from threading import Thread
import queue
def consumer(q,name):
while True:
food = q.get()
time.sleep(random.uniform(0.1,1)) # 消费快
print(f'“{name}”吃了“{food}”')
q.task_done()
def producer(q,name):
for i in range(1,6):
time.sleep(random.uniform(1,2)) # 生产慢
food = f'{name}{i}'
print(f'“{name}店”生产了“{food}”')
q.put(food)
q.join()
if __name__ == '__main__':
q = queue.Queue(10)
producer_table = ['蛋糕','面包','冰淇淋']
for i in producer_table:
p = Thread(target=producer,args=(q,i))
p.start()
customer_table = ['张三','李四','王五','赵六']
for i in customer_table:
c = Thread(target=consumer,args=(q,i))
c.daemon = True
c.start()
输出:
有兴趣的朋友可以复制代码自行执行,因为每次运行结果都不一致。但是在生产者生产完毕、消费者消费完毕后,程序可以正常结束。
说明:
后进先出LifoQueue
后进先出队列用法:
from queue import LifoQueue # 后进先出队列
q = LifoQueue()
for i in range(6):
q.put(i)
while not q.empty():
print(q.get())
输出:
5
4
3
2
1
0
说明:
后进先出队列就是栈,除了消息的取回顺序和Queue相反之外,其他用法完全一致。
优先级PriorityQueue
优先级队列使用案例:
from queue import PriorityQueue # 优先级队列
priq = PriorityQueue()
priq.put((0,'aaa'))
priq.put((1,'bbb'))
priq.put((2,'cccc'))
priq.put((0,'dddd'))
priq.put((0,'eeee'))
priq.put((1,'ffff'))
while not priq.empty():
print(priq.get()[1])
输出:
aaa
dddd
eeee
bbb
ffff
cccc
说明:
优先级队列的item参数是元组,元组的第一项是优先级号(数字类型,数字越小越早取、数字越大越晚取,可以是整数、浮点数、正数或负数)、第二项是数据。
优先级队列除了消息的取回顺序和Queue不一样之外,其他用法完全一致。