[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教程
官方文档

posted @   英击长空  阅读(157)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示