Python collections.deque双边队列原理详解


Posted in Python onOctober 05, 2020

队列是一种只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

在Python文档中搜索队列(queue)会发现,Python标准库中包含了四种队列,分别是queue.Queue / asyncio.Queue / multiprocessing.Queue / collections.deque。

collections.deque

deque是双端队列(double-ended queue)的缩写,由于两端都能编辑,deque既可以用来实现栈(stack)也可以用来实现队列(queue)。

deque支持丰富的操作方法,主要方法如图:

Python collections.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是原子操作(一行字节码)。

Python collections.deque双边队列原理详解

综上,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中则是以返回协程对象的方式执行,具体差异如下表:

  queue.Queue asyncio.Queue
介绍 同步队列 asyncio队列
线程安全
超时机制 通过timeout参数实现 通过asyncio.wait_for()方法实现
qsize() 预估的队列长度(获取qsize到下一个操作之间,queue有可能被其它的线程修改,导致qsize大小发生变化) 准确的队列长度(由于是单线程,所以queue不会被其它线程修改)
put() / set() put(item, block=True, timeout=None),可以通过设置block是否为True来配置put和set方法是否为阻塞,并且可以为阻塞操作设置最大时长timeout,block为False时行为和put_nowait()方法一致。 put()方法会返回一个协程对象,所以没有block参数和timeout参数,如果需要非阻塞方法,可以使用put_nowait(),如果需要对阻塞方法应用超时,可以使用coroutine asyncio.wait_for()。

multiprocessing.Queue

multiprocessing提供了三种队列,分别是Queue、SimpleQueue、JoinableQueue。

Python collections.deque双边队列原理详解

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 相关文章推荐
python中pycurl库的用法实例
Sep 30 Python
Python实现获取网站PR及百度权重
Jan 21 Python
python爬虫 正则表达式使用技巧及爬取个人博客的实例讲解
Oct 20 Python
Python算法之图的遍历
Nov 16 Python
分析Python中解析构建数据知识
Jan 20 Python
python 信息同时输出到控制台与文件的实例讲解
May 11 Python
Python实现的redis分布式锁功能示例
May 29 Python
python三大神器之fabric使用教程
Jun 10 Python
pytorch 实现将自己的图片数据处理成可以训练的图片类型
Jan 08 Python
基于python监控程序是否关闭
Jan 14 Python
Python实现对adb命令封装
Mar 06 Python
Python + opencv对拍照得到的图片进行背景去除的实现方法
Nov 18 Python
Python全局变量与global关键字常见错误解决方案
Oct 05 #Python
Python定时任务框架APScheduler原理及常用代码
Oct 05 #Python
Python xmltodict模块安装及代码实例
Oct 05 #Python
Python pathlib模块使用方法及实例解析
Oct 05 #Python
Python fileinput模块如何逐行读取多个文件
Oct 05 #Python
Python利用Pillow(PIL)库实现验证码图片的全过程
Oct 04 #Python
Python中random模块常用方法的使用教程
Oct 04 #Python
You might like
php,不用COM,生成excel文件
2006/10/09 PHP
给php新手谈谈我的学习心得
2007/02/25 PHP
PHP+Mysql实现多关键字与多字段生成SQL语句的函数
2014/11/05 PHP
php判断类是否存在函数class_exists用法分析
2014/11/14 PHP
才发现的超链接js导致网页中GIF动画停止的解决方法
2007/11/02 Javascript
很多人都是用下面的js刷新站IP和PV
2008/09/05 Javascript
javascript 嵌套的函数(作用域链)
2010/03/15 Javascript
js列举css中所有图标的实现代码
2011/07/04 Javascript
Jquery attr(&quot;checked&quot;) 返回checked或undefined 获取选中失效
2013/10/10 Javascript
手机端页面rem宽度自适应脚本
2015/05/20 Javascript
JS鼠标拖拽实例分析
2015/11/23 Javascript
JavaScript类型系统之Object详解
2016/01/07 Javascript
JS Attribute属性操作详解
2016/05/19 Javascript
详细探究ES6之Proxy代理
2016/07/22 Javascript
AngularJS教程之简单应用程序示例
2016/08/16 Javascript
详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】
2016/12/19 Javascript
JS实现移动端实时监听输入框变化的实例代码
2017/04/12 Javascript
Vuex 快速入门(简单易懂)
2018/09/20 Javascript
解决Vue-cli npm run build生产环境打包,本地不能打开的问题
2018/09/20 Javascript
three.js 利用uv和ThreeBSP制作一个快递柜功能
2020/08/18 Javascript
Ant Design的Table组件去除
2020/10/24 Javascript
vue+iview实现分页及查询功能
2020/11/17 Vue.js
[54:02]2018DOTA2亚洲邀请赛 4.1 小组赛 B组 IG vs VGJ.T
2018/04/03 DOTA
[00:32]2018DOTA2亚洲邀请赛Secret出场
2018/04/03 DOTA
[01:12:35]Spirit vs Navi Supermajor小组赛 A组败者组第一轮 BO3 第二场 6.2
2018/06/03 DOTA
python制作小说爬虫实录
2017/08/14 Python
在pycharm中设置显示行数的方法
2019/01/16 Python
tensorflow中tf.reduce_mean函数的使用
2020/04/19 Python
澳洲在线厨具商店:Kitchen Style
2018/05/05 全球购物
英国天然有机美容护肤品:Neal’s Yard Remedies
2018/05/05 全球购物
自荐信格式的六要素
2013/09/21 职场文书
商务英语应届生自我鉴定
2013/12/08 职场文书
基层干部十八大感言
2014/01/19 职场文书
大学学雷锋活动总结
2014/06/26 职场文书
社区党员干部承诺书
2015/05/04 职场文书
小兵张嘎观后感300字
2015/06/03 职场文书