「这是我参与2022首次更文挑战的第17天,活动详情查看:2022首次更文挑战」。
正式的Python专栏第66篇,同学站住,别错过这个从0开始的文章!
之前看内置队列发现才几百行代码,没细看。 本来是想’简单‘写写文章,速读一下,可是这个队列用的其他库还挺多的,所以篇幅就更大了。
一大意容易栽坑里挖,走不出来,所以尽量克制一点,今天我们看看简单队列:SimpleQueue
在看之前,很有必要介绍一下:双端队列
因为SimpleQueue的源码里面主要用了这个队列,所以需要先铺垫解释
简单来说,双端队列 就是可以两边都插入数据的队列,两边都取出数据的队列。
哇塞,很猛的样子!(其实内部也是有很多设计,双端队列这个坑这里不深挖了,小短文是写不完的。)
from collections import deque
dq = deque([])
上面是创建双端队列的代码,它有一套对称的添加/获取元素的方法,比如append,appendleft 或者 pop ,popleft(对应的是右边加新元素,左边加新元素 和 右边取出新元素,左边取出新元素),还有很多方法,但是本文不多谈。
学委这里写了一个demo,展示双端队列左右端的元素操作:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2022/2/17 11:30 下午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : dequedemo.py
# @Project : hello
from collections import deque
dq = deque([]) #Double-Ended Queue
dq.append("01") #append即可,它就是append right
dq.append("02")
dq.append("03")
print("dq:", dq)
dq.appendleft("a")
dq.appendleft("b")
dq.appendleft("c")
print("dq:", dq)
# 右边取出一个元素
v = dq.pop()
print("v:", v)
print("dq:", dq)
# 左边取出一个元素
v = dq.popleft()
print("v:", v)
print("dq:", dq)
运行效果如下:
好,简单队列隆重登场
这个之前文章写过demo了。
打好了双端队列基础之后,我们看简单队列就简单多了。
几乎都不用解析了。。。 当然也不是。
我们看到简单队列在初始化的时候,创建了一个信号量为0的变量。
好家伙,这样做,只能是调用了release方法之后,才能acquire了, 不清楚信号量的朋友可以看:学委之前写的信号量相关文章
class _PySimpleQueue:
def __init__(self):
self._queue = deque()
self._count = threading.Semaphore(0)
def put(self, item, block=True, timeout=None):
self._queue.append(item)
self._count.release()
def get(self, block=True, timeout=None):
if timeout is not None and timeout < 0:
raise ValueError("'timeout' must be a non-negative number")
if not self._count.acquire(block, timeout):
raise Empty
return self._queue.popleft()
def put_nowait(self, item):
return self.put(item, block=False)
def get_nowait(self):
return self.get(block=False)
def empty(self):
return len(self._queue) == 0
def qsize(self):
return len(self._queue)
if SimpleQueue is None:
SimpleQueue = _PySimpleQueue
我们重点看一下put方法。
put方法,追加元素(每次放入都在队列右边加入),同时释放一个信号量(可用信号量+1)。 仅此而已。
下面是get方法解析:
默认情况下创建了简单队列,直接去get,线程会一直等待,知道有元素放入简单队列(也就是有线程调用了put方法)。
如果是get传入block=False,并且没有设置timeout,那就是get_nowait的情况,这个时候信号量acquire获取的值是False,抛出空值异常了。
当我们放了元素到简单队列(或者多个),后面加的元素都是在deque右边的,最左边的元素就是最新加入元素,所以程序直接popleft。
这样简单队列通过deque保证了元素先进先出原则
所以get_nowait, pop_nowait等等这些都不需要多解释。
而qsize,empty这些常规队列配套方法看过前面的文章都知道。
总结
简单队列内核用了双端队列,实现元素的添加,删除,再说一次‘先进先出’。而且它是线程安全的。
喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏
持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!