Python 内置队列 queue快速一览

本文介绍了Python内置的线程安全队列,包括Queue、LifoQueue和PriorityQueue。Queue是基础队列,LifoQueue是先进后出(FIFO)队列,PriorityQueue是优先级队列,适用于多线程场景中的数据交互。文章通过实例展示了如何使用这些队列,并对比了Queue和SimpleQueue的区别,强调了它们在并发环境下的安全性。

正式的Python专栏第62篇,同学站住,别错过这个从0开始的文章!

之前的多线程解决线程安全的时候,学委展示了两篇关于队列的 带你验收一款线程安全的队列 使用队列改造转账场景线程安全问题

刚好这个库比较简单,不超过500行,挨着多线程,那就顺便把队列这个库。

内置的队列都有哪些?

打开源码,除了开头定义了空队列Empty异常和满队列异常Full异常。

主要提供了两类队列:Queue及其衍生类 vs SimpleQueue

Queue和它的衍生类

  • LifoQueue:先进后出队列(LastInFirstOut Q)
  • PriorityQueue:优先队列
  • Queue:其他队列的父类。(见下图)

屏幕快照 2022-02-02 上午12.12.32.png

之前说过这个Queue为线程安全的队列,同样的LifoQueue和PriorityQueue也是线程安全的。

可以放心的使用它放在多线程场景使用,进行多线程的数据交互。

然后这里稍微展示一下:LifoQueue:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/2/2 12:43 下午
# @Author : LeiXueWei
# @优快云/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : lifoqdemo.py
# @Project : hello
import queue
import threading
import time

lifoq = queue.LifoQueue(3)  # 虎年就设置一个三吧

lifoq.put("一祝各位朋友们新年快乐")
lifoq.put("二祝各位朋友们身体健康")
lifoq.put("三祝各位朋友们虎年大吉")


def more_blessing():
    count = 0
    while count < 3:
        print("wait....")
        count += 1
        lifoq.put("其他的祝福%s" % count)


def get_from_q():
    while not lifoq.empty():
        print("%s ㊗️:%s" % (threading.current_thread().name, lifoq.get()))


threading.Thread(target=get_from_q, name="学委给朋友们拜年了").start()
threading.Thread(target=more_blessing, name="送更多的祝福").start()

简单队列

SimpleQueue:基于deque和Semaphore实现的简单队列。

但是它也是一个线程安全的类。

Queue和SimpleQueue两者之间的联系:

先把实现抽离,我们可以看到,Queue这个类,对多个线程交互上提供了更多的原生设计,像join和task_done.

因为Queue是可以设置限额的,所以多了一个full方法。而SimpleQueue是一个没有边界的队列,不需要这个检查。

但是两者底层都是使用了deque这个结构,所以如果我们想要知道线程安全的细节,还需要后面再挖一挖。

为了方便比对,这个是删减版的Queue实现:

class Queue:
    '''Create a queue object with a given maximum size.

    If maxsize is <= 0, the queue size is infinite.
    '''

    def __init__(self, maxsize=0):
        self.maxsize = maxsize
        self._init(maxsize)
        self.mutex = threading.Lock()
        self.not_empty = threading.Condition(self.mutex)
        self.not_full = threading.Condition(self.mutex)
        self.all_tasks_done = threading.Condition(self.mutex)
        self.unfinished_tasks = 0

    def task_done(self):
        pass

    def join(self):
        pass

    def qsize(self):
        pass

    def empty(self):
        pass

    def full(self):
        pass

    def put(self, item, block=True, timeout=None):
        pass

    def get(self, block=True, timeout=None):
        pass

    def put_nowait(self, item):
        pass

    def get_nowait(self):
        pass

    # Override these methods to implement other queue organizations
    # (e.g. stack or priority queue).
    # These will only be called with appropriate locks held

    # Initialize the queue representation
    def _init(self, maxsize):
        self.queue = deque() #底层还是使用deque这个数据结构

    def _qsize(self):
        return len(self.queue)

    # Put a new item in the queue
    def _put(self, item):
        self.queue.append(item)

    # Get an item from the queue
    def _get(self):
        

为了方便比对,这是删减版本的SimpleQueue:

class SimpleQueue: #_PySimpleQueue


    def __init__(self):
        self._queue = deque()
        self._count = threading.Semaphore(0)

    def put(self, item, block=True, timeout=None):
        pass

    def get(self, block=True, timeout=None):
        pass

    def put_nowait(self, item):
        pass

    def get_nowait(self):
        pass

    def empty(self):
        pass

    def qsize(self):
        pass

更多内容可以查看下面的文章,学委准备了一些实例代码结合场景分享这些内置队列。

Python 内置队列 FIFO vs FILO 队列对比展示

Python 内置优先队列PriorityQueue 高级餐厅用餐场景展示

Python 内置优先队列PriorityQueue 代码解析

Python 内置队列 SimpleQueue 代码解析

喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏

持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!

非常好!我们来详细讲解 Python 中的 `deque` 这个队列库,包括它的作用、使用方法、常见操作以及为什么在拓扑排序中会使用它。 --- ## 🧠 什么是 `deque`? `deque` 是 `collections` 模块中的一个**双端队列(double-ended queue)**,它支持从**头部和尾部高效地添加或删除元素**。 它非常适合用作: - 队列(先进先出 FIFO) - 栈(后进先出 LIFO) - 滑动窗口 - 拓扑排序 - BFS(广度优先搜索) --- ## 📦 如何导入和初始化 deque? ```python from collections import deque # 初始化一个空的 deque dq = deque() # 初始化一个带有初始值的 deque dq = deque([1, 2, 3]) ``` --- ## 🧩 常见操作一览: | 操作 | 方法 | 说明 | |------|------|------| | 添加元素到队尾 | `append(x)` | 类似列表的 append | | 添加元素到队首 | `appendleft(x)` | 插入到最前面 | | 从队尾删除 | `pop()` | 删除并返回最后一个元素 | | 从队首删除 | `popleft()` | 删除并返回第一个元素 | | 清空队列 | `clear()` | 清空所有元素 | | 查看所有元素 | `list(deque)` | 转换为列表查看 | | 判断是否为空 | `len(deque) == 0` | 为空返回 True | --- ## 🧪 示例代码: ```python from collections import deque dq = deque() # 添加元素到队尾 dq.append(1) dq.append(2) dq.append(3) print("添加后:", dq) # deque([1, 2, 3]) # 从队首取出元素 first = dq.popleft() print("取出第一个元素:", first) # 1 print("取出后:", dq) # deque([2, 3]) # 添加元素到队首 dq.appendleft(0) print("添加到队首后:", dq) # deque([0, 2, 3]) # 从队尾取出 last = dq.pop() print("取出最后一个元素:", last) # 3 print("取出后:", dq) # deque([0, 2]) ``` --- ## 🧠 为什么拓扑排序中要用 `deque`? 在拓扑排序中,我们需要一个**先进先出的队列**来保存当前可以学习的课程(即入度为 0 的课程)。 使用 `deque` 的优势: - `popleft()` 时间复杂度是 O(1),效率高 - 可以动态地添加和删除元素 - 非常适合 BFS(广度优先遍历)的结构 --- ## 🧾 拓扑排序中典型用法: ```python from collections import deque def topological_sort(numCourses, prerequisites): graph = [[] for _ in range(numCourses)] in_degree = [0] * numCourses for course, prereq in prerequisites: graph[prereq].append(course) in_degree[course] += 1 queue = deque([i for i in range(numCourses) if in_degree[i] == 0]) result = [] while queue: current = queue.popleft() result.append(current) for neighbor in graph[current]: in_degree[neighbor] -= 1 if in_degree[neighbor] == 0: queue.append(neighbor) if len(result) != numCourses: return [] # 存在环,无法完成拓扑排序 return result ``` --- ## ✅ 总结一句话: > `deque` 是一个高效的双端队列结构,非常适合用于拓扑排序、BFS、滑动窗口等需要频繁在队列两端操作的场景。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雷学委

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值