详解Python中的四种队列
作者:simpleapples 发布时间:2021-05-10 01:48:04
队列是一种只允许在一端进行插入操作,而在另一端进行删除操作的线性表。
在Python文档中搜索队列(queue)会发现,Python标准库中包含了四种队列,分别是queue.Queue / asyncio.Queue / multiprocessing.Queue / collections.deque。
collections.deque
deque是双端队列(double-ended queue)的缩写,由于两端都能编辑,deque既可以用来实现栈(stack)也可以用来实现队列(queue)。
deque支持丰富的操作方法,主要方法如图:
相比于list实现的队列,deque实现拥有更低的时间和空间复杂度。list实现在出队(pop)和插入(insert)时的空间复杂度大约为O(n),deque在出队(pop)和入队(append)时的时间复杂度是O(1)。
deque也支持in操作符,可以使用如下写法:
q = collections.deque([1, 2, 3, 4])
print(5 in q) # False
print(1 in q) # True
deque还封装了顺逆时针的旋转的方法:rotate。
# 顺时针
q = collections.deque([1, 2, 3, 4])
q.rotate(1)
print(q) # [4, 1, 2, 3]
q.rotate(1)
print(q) # [3, 4, 1, 2]
# 逆时针
q = collections.deque([1, 2, 3, 4])
q.rotate(-1)
print(q) # [2, 3, 4, 1]
q.rotate(-1)
print(q) # [3, 4, 1, 2]
线程安全方面,collections.deque中的append()、pop()等方法都是原子操作,所以是GIL保护下的线程安全方法。
static PyObject *
deque_append(dequeobject *deque, PyObject *item) {
Py_INCREF(item);
if (deque_append_internal(deque, item, deque->maxlen) < 0)
return NULL;
Py_RETURN_NONE;
}
通过dis方法可以看到,append是原子操作(一行字节码)。
综上,collections.deque是一个可以方便实现队列的数据结构,具有线程安全的特性,并且有很高的性能。
queue.Queue & asyncio.Queue
queue.Queue和asyncio.Queue都是支持多生产者、多消费者的队列,基于collections.deque,他们都提供了Queue(FIFO队列)、PriorityQueue(优先级队列)、LifoQueue(LIFO队列),接口方面也相同。
区别在于queue.Queue适用于多线程的场景,asyncio.Queue适用于协程场景下的通信,由于asyncio的加成,queue.Queue下的阻塞接口在asyncio.Queue中则是以返回协程对象的方式执行,具体差异如下表:
multiprocessing.Queue
multiprocessing提供了三种队列,分别是Queue、SimpleQueue、JoinableQueue。
multiprocessing.Queue既是线程安全也是进程安全的,相当于queue.Queue的多进程克隆版。和threading.Queue很像,multiprocessing.Queue支持put和get操作,底层结构是multiprocessing.Pipe。
multiprocessing.Queue底层是基于Pipe构建的,但是数据传递时并不是直接写入Pipe,而是写入进程本地buffer,通过一个feeder线程写入底层Pipe,这样做是为了实现超时控制和非阻塞put/get,所以Queue提供了join_thread、cancel_join_thread、close函数来控制feeder的行为,close函数用来关闭feeder线程、join_thread用来join feeder线程,cancel_join_thread用来在控制在进程退出时,不自动join feeder线程,使用cancel_join_thread有可能导致部分数据没有被feeder写入Pipe而导致的数据丢失。
和threading.Queue不同的是,multiprocessing.Queue默认不支持join()和task_done操作,这两个支持需要使用mp.JoinableQueue对象。
SimpleQueue是一个简化的队列,去掉了Queue中的buffer,没有了使用Queue可能出现的问题,但是put和get方法都是阻塞的并且没有超时控制。
总结
通过对比可以发现,上述四种结构都实现了队列,但是用处却各有偏重,collections.deque在数据结构层面实现了队列,但是并没有应用场景方面的支持,可以看做是一个基础的数据结构。queue模块实现了面向多生产线程、多消费线程的队列,asyncio.queue模块则实现了面向多生产协程、多消费协程的队列,而multiprocessing.queue模块实现了面向多成产进程、多消费进程的队列。
以上所述是小编给大家介绍的Python中的四种队列网站的支持!
来源:https://juejin.im/post/5b022e456fb9a07aaf35810d
猜你喜欢
- 记录一下关于geemap的安装步骤,geemap是基于GEE由吴秋生老师二次开发的一个包,geemap主要使用python来进行实现相关功能
- 这篇文章主要介绍了通过实例了解Python str()和repr()的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- python的numpy库提供矩阵运算的功能,因此我们在需要矩阵运算的时候,需要导入numpy的包。一、numpy的导入和使用from&nb
- 本文实例讲述了django框架使用模板。分享给大家供大家参考,具体如下:models.py:from django.db import mo
- 八皇后问题描述:在一个8✖️8的棋盘上,任意摆放8个棋子,要求任意两个棋子不能在同一行,同一列,同一斜线上,问有多少种解法。规则分析:任意两
- 前言记得刚入门那个时候,自己处理编码转换问题往往是“百度:url解码、base64加密、hex……”,或者是使用一款叫做“小葵多功能转换工具
- 功能super功能:super函数是子类用于调用父类(超类)的一个方法。用法1.在子类 __init__() 方法中正确的初始化父类,保证相
- 提高SQL执行效率的几点建议:◆尽量不要在where中包含子查询;关于时间的查询,尽量不要写成:where to_char(dif_date
- PyQt5中信号与槽可以说是对事件处理机制的高级封装,如果说事件是用来创建窗口控件的,那么信号与槽就是用来对这个控件进行使用的,比如一个按钮
- 阅读上一章:chapter 5 表单Chapter 6 <strong>,<em>与其他短语元素在引言和前面的章节中
- 目录项目地址运行环境运行方法数据爬取(jd.comment.py)模型训练(train.py)情感分析(sentiment.analysis
- 虽然网上有很多python开发环境搭建的文章,不过重复造轮子还是要的,记录一下过程,方便自己以后配置,也方便正在学习中的同事配置他们的环境。
- 网络爬虫由于一个ip频繁访问同一网站,容易返回456或者被长时间封禁。特别的本机有socks5客户端的设置如下,前提是已经安装了socks5
- 前言和网络 IO 一样,文件读写同样是一个费事的操作。默认情况下,Python 使用的是系统的阻塞读写。这意味着在 asyncio 中如果调
- 在我们学习的过程中会遇到这么样的问题,就是在我们学习的过程中会发现需要分页处理,这里呢,给大家介绍书上说的分页。@app.route(
- 一份完全按照李航<<统计学习方法>>介绍的HMM代码,供大家参考,具体内容如下#coding=utf8 '&
- SQL Server会把经常使用到的数据缓存在内存里(就是数据页缓存),用以提高数据访问速度。因为磁盘访问速度远远低于内存,所以减少磁盘访问
- 前面学习过Meanshift算法,在观察这个结果标记时,会发现有这样一个问题,如下图:汽车比较远时,用一个很小的窗口就可以把它框住,这是符合
- os模块提供了对目录或者文件的新建/删除/查看文件属性,还提供了对文件以及目录的路径操作。比如说:绝对路径,父目录…… 但是,o
- 在矩阵应用的过程中,经常需要使用随机数,那么怎么使用numpy 产生随机数呢 ,为此专门做一个总结。random模块用于生成随机数,下面是一