[python学习总结]队列
队列
概述
collections模块
collections.deque ---双端队列
queue模块中提供了同步的、线程安全的队列类,
包括FIFO(先入先出)队列Queue,
LIFO(后入先出)队列LifoQueue,
优先级队列PriorityQueue。
class queue.SimpleQueue¶
其他模块
asyncio.Queue / --异步模块
multiprocessing.Queue / -- 并发执行
collections模块(线程安全的双端队列)
deque (双端队列)
from collections import deque
# 创建一个空的deque
d = deque()
# 在队列尾部添加元素
d.append(1)
d.append(2)
d.append(3)
print(d) # 输出: deque([1, 2, 3])
# 在队列头部添加元素
d.appendleft(0)
print(d) # 输出: deque([0, 1, 2, 3])
# 从队列尾部删除元素
last_element = d.pop()
print(last_element) # 输出: 3
print(d) # 输出: deque([0, 1, 2])
# 从队列头部删除元素
first_element = d.popleft()
print(first_element) # 输出: 0
print(d) # 输出: deque([1, 2])
# 获取队列长度
length = len(d)
print(length) # 输出: 2
# 判断元素是否在队列中
if 1 in d:
print("1 is in the deque")
else:
print("1 is not in the deque")
# 遍历队列中的元素
for element in d:
print(element)
Queue模块(线程安全 )
Python的Queue模块提供一种适用于多线程编程的FIFO实现。
它可用于在生产者(producer)和消费者(consumer)之间线程安全(thread-safe)地传递消息或其它数据,因此多个线程可以共用同一个Queue实例。Queue的大小(元素的个数)可用来限制内存的使用。
queue模块中的常用方法:
变量
queue.full 与 maxsize 大小对应
方法
queue.qsize() 返回队列的大小
queue.empty() 如果队列为空,返回True,反之False
queue.full() 如果队列满了,返回True,反之False
queue.get([block[, timeout]])获取队列,timeout等待时间
注:这个方法会阻塞直到队列中有元素可用,然后返回队列中的第一个元素。
queue.get_nowait() 相当queue.get(False)
queue.put(item)
注这里的full指的是超出 maxsize
写入队列,timeout等待时间,如果超时还没有空位置,则会报一个full异常
queue.put_nowait(item) 相当queue.put(item, False) 马上插入,如果不为空马上报异常
queue.task_done() 在完成一项工作之后,queue.task_done()函数向任务已经完成的队列发送一个信号
queue.join() 实际上意味着等到队列为空,再执行别的操作
注:获取头部或者尾部元素
好像没有办法
FIFO Queue (先进先出)
Queue类实现了一个基本的先进先出(FIFO)容器,使用put()将元素添加到序列尾端,get()从队列尾部移除元素。
from queue import Queue
def test_queue():
q=Queue(10)
for i in range(5):
q.put(i)
while not q.empty():
print(q.get())
LIFO Queue(也就是栈)
与标准FIFO实现Queue不同的是,LifoQueue使用后进先出序(会关联一个栈数据结构)。
def test_LifoQueue():
import queue
# queue.LifoQueue() #后进先出->堆栈
q = queue.LifoQueue(3)
q.put(1)
q.put(2)
q.put(3)
print(q.get())
print(q.get())
print(q.get())
Priority Queue(优先队列)
除了按元素入列顺序外,有时需要根据队列中元素的特性来决定元素的处理顺序。例如,财务部门的打印任务可能比码农的代码打印任务优先级更高。PriorityQueue依据队列中内容的排序顺序(sort order)来决定那个元素将被检索。
def test_PriorityQueue():
import queue
# queue.PriorityQueue() #优先级
q = queue.PriorityQueue(3) # 优先级,优先级用数字表示,数字越小优先级越高
q.put((10, 'a'))
q.put((-1, 'b'))
q.put((100, 'c'))
print(q.get())
print(q.get())
print(q.get())
class queue.SimpleQueue¶
无界的 FIFO 队列构造函数。简单的队列,缺少任务跟踪等高级功能。
在 3.7 版本加入.
线程安全演示
queue.Queue 是 Python 中 queue 模块提供的一个线程安全的队列类,用于在多线程之间传递数据。它提供了 put() 和 get() 方法,分别用于向队列中添加元素和从队列中获取元素。以下是一个简单的使用示例:
在这个示例中,我们定义了一个生产者线程和一个消费者线程。生产者线程每隔1秒向队列中添加一个元素,消费者线程每隔2秒从队列中获取一个元素并处理。我们使用 queue.Queue 实例化一个队列对象,并将其传递给生产者和消费者线程。最后,我们启动生产者和消费者线程,并在生产者线程结束后向队列中添加一个 None 元素,以通知消费者线程退出。
注意:由于queue是线程安全的,所以不需要使用锁
import threading
import queue
def producer(q):
for i in range(5):
print(f"生产者生产了{i}")
q.put(i) # 注意这里如果满了的话,会报异常
time.sleep(1)
def consumer(q):
while True:
item = q.get()
if item is None:
break
print(f"消费者消费了{item}")
time.sleep(2)
if __name__ == "__main__":
q = queue.Queue()
producer_thread = threading.Thread(target=producer, args=(q,))
consumer_thread = threading.Thread(target=consumer, args=(q,))
producer_thread.start()
consumer_thread.start()
producer_thread.join()
q.put(None) # 通知消费者退出
consumer_thread.join()
几个问题
queue 会满吗
这个队列默认没有最大容量限制,所以从技术上讲,它不会“满”,因为它可以无限地增长。然而,实际上,由于内存限制,队列最终会遇到内存不足的问题,这会导致程序抛出 MemoryError 异常。
在设计程序时,应该尽量避免队列无限增长的情况,通过设定合理的队列大小或者在队列达到一定大小时采取措施(比如减少生产者的工作量或者清理不再需要的数据)。
另外,queue.Queue() 有一个 maxsize 参数,可以设置队列的最大容量。如果设置了 maxsize,那么队列在达到这个容量之后,新的元素将无法加入,直到队列中有元素被取出。这时候,如果尝试往已满的队列中添加元素,程序将会抛出 queue.Full 异常。
queue 如果取第一个元素
没有这种方法,只能用get
Queue模块 是如何实现线程安全的
queue.Queue 类是 Python 的 queue 模块提供的一个线程安全的队列实现。它使用了内部锁(lock)机制来保证在多线程环境中对队列的操作是安全的。这意味着同时只有一个线程可以执行队列的 put、get、empty 等操作,从而防止了多线程同时操作队列时可能出现的竞态条件(race condition)。
以下是 queue.Queue 类实现线程安全的一些关键点:
互斥锁(Mutex):queue.Queue 类使用了互斥锁来保护队列数据结构,确保每次只有一个线程可以访问队列。当一个线程正在执行队列操作时,其他线程必须等待直到锁被释放。
条件变量(Condition):在某些情况下,queue.Queue 类还使用了条件变量。例如,当队列满时,生产者线程需要等待,直到消费者线程消费了一些元素,使得队列有空间可用。条件变量允许线程在某些条件不满足时挂起,直到这些条件被另一个线程设置。
原子操作:queue.Queue 类使用了 Python 的 threading 模块提供的原子操作来执行诸如增加计数器、检查队列是否为空等操作,这些操作在多线程环境中是安全的。
数据结构的选择:queue.Queue 类内部使用了一些线程安全的数据结构,比如 collections.deque,这是一个线程安全的双端队列。
异常处理:在处理队列操作时,queue.Queue 类会捕获可能发生的异常,并确保在异常情况下释放锁,以避免死锁。
总的来说,queue.Queue 类通过使用锁和条件变量来保证线程在访问队列时的同步,通过原子操作来保证操作的原子性,以及通过选择线程安全的数据结构来构建一个线程安全的队列。这些机制共同工作,确保了 queue.Queue 类在多线程环境下的正确性和稳定性。
附件
https://www.cnblogs.com/ranjiewen/p/10218751.html
刘江的python教程
官方文档
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端