导航:首页 > 编程语言 > python队列类

python队列类

发布时间:2023-06-11 23:02:22

‘壹’ python实现简单多线程任务队列

Python实现简单多线程任务队列
最近我在用梯度下降算法绘制神经网络的数据时,遇到了一些算法性能的问题。梯度下降算法的代码如下(伪代码):
defgradient_descent(): # the gradient descent code plotly.write(X, Y)
一般来说,当网络请求 plot.ly 绘图时会阻塞等待返回,于是也会影响到其他的梯度下降函数的执行速度。
一种解决办法是每调用一次 plotly.write 函数就开启一个新的线程,但是这种方法感觉不是很好。 我不想用一个像 cerely(一种分布式任务队列)一样大而全的任务队列框架,因为框架对于我的这点需求来说太重了,并且我的绘图也并不需要 redis 来持久化数据。
那用什么办法解决呢?我在 python 中写了一个很小的任务队列,它可以在一个单独的线程中调用 plotly.write函数。下面是程序代码。
classTaskQueue(Queue.Queue):
首先我们继承 Queue.Queue 类。从 Queue.Queue 类可以继承 get 和 put 方法,以及队列的行为。
def__init__(self, num_workers=1): Queue.Queue.__init__(self) self.num_workers=num_workers self.start_workers()
初始化的时候,我们可以不用考虑工作线程的数量。
defadd_task(self, task,*args,**kwargs): args=argsor() kwargs=kwargsor{} self.put((task, args, kwargs))
我们把 task, args, kwargs 以元组的形式存储在队列中。*args 可以传递数量不等的参数,**kwargs 可以传递命名参数。
defstart_workers(self): foriinrange(self.num_workers): t=Thread(target=self.worker) t.daemon=True t.start()
我们为每个 worker 创建一个线程,然后在后台删除。
下面是 worker 函数的代码:
defworker(self): whileTrue: tupl=self.get() item, args, kwargs=self.get() item(*args,**kwargs) self.task_done()
worker 函数获取队列顶端的任务,并根据输入参数运行,除此之外,没有其他的功能。下面是队列的代码:
我们可以通过下面的代码测试:
defblokkah(*args,**kwargs): time.sleep(5) print“Blokkah mofo!” q=TaskQueue(num_workers=5) foriteminrange(1): q.add_task(blokkah) q.join()# wait for all the tasks to finish. print“Alldone!”
Blokkah 是我们要做的任务名称。队列已经缓存在内存中,并且没有执行很多任务。下面的步骤是把主队列当做单独的进程来运行,这样主程序退出以及执行数据库持久化时,队列任务不会停止运行。但是这个例子很好地展示了如何从一个很简单的小任务写成像工作队列这样复杂的程序。
defgradient_descent(): # the gradient descent code queue.add_task(plotly.write, x=X, y=Y)
修改之后,我的梯度下降算法工作效率似乎更高了。如果你很感兴趣的话,可以参考下面的代码。 classTaskQueue(Queue.Queue): def__init__(self, num_workers=1):Queue.Queue.__init__(self)self.num_workers=num_workersself.start_workers() defadd_task(self, task,*args,**kwargs):args=argsor()kwargs=kwargsor{}self.put((task, args, kwargs)) defstart_workers(self):foriinrange(self.num_workers):t=Thread(target=self.worker)t.daemon=Truet.start() defworker(self):whileTrue:tupl=self.get()item, args, kwargs=self.get()item(*args,**kwargs)self.task_done() deftests():defblokkah(*args,**kwargs):time.sleep(5)print"Blokkah mofo!" q=TaskQueue(num_workers=5) foriteminrange(10):q.add_task(blokkah) q.join()# block until all tasks are doneprint"All done!" if__name__=="__main__":tests()

‘贰’ python实现堆栈与队列的方法

python实现堆栈与队列的方法
本文实例讲述了python实现堆栈与队列的方法。分享给大家供大家参考。具体分析如下:
1、python实现堆栈,可先将Stack类写入文件stack.py,在其它程序文件中使用from stack import Stack,然后就可以使用堆栈了。
stack.py的程序:
代码如下:class Stack():
def __init__(self,size):
self.size=size;
self.stack=[];
self.top=-1;
def push(self,ele): #入栈之前检查栈是否已满
if self.isfull():
raise exception("out of range");
else:
self.stack.append(ele);
self.top=self.top+1;
def pop(self): # 出栈之前检查栈是否为空
if self.isempty():
raise exception("stack is empty");
else:
self.top=self.top-1;
return self.stack.pop();

def isfull(self):
return self.top+1==self.size;
def isempty(self):
return self.top==-1;
再写一个程序文件,stacktest.py,使用栈,内容如下:
代码如下:#!/usr/bin/python
from stack import Stack
s=Stack(20);
for i in range(3):
s.push(i);
s.pop()
print s.isempty();

2、python 实现队列:
复制代码代码如下:class Queue():
def __init__(self,size):
self.size=size;
self.front=-1;
self.rear=-1;
self.queue=[];
def enqueue(self,ele): #入队操作
if self.isfull():
raise exception("queue is full");
else:
self.queue.append(ele);
self.rear=self.rear+1;
def dequeue(self): #出队操作
if self.isempty():
raise exception("queue is empty");
else:
self.front=self.front+1;
return self.queue[self.front];
def isfull(self):
return self.rear-self.front+1==self.size;
def isempty(self):
return self.front==self.rear;

q=Queue(10);
for i in range(3):
q.enqueue(i);
print q.dequeue();
print q.isempty();
希望本文所述对大家的Python程序设计有所帮助。

‘叁’ python基础(21)-线程通信

到这里,我们要聊一下线程通信的内容;
首先,我们抛开语言不谈,先看看比较基础的东西,线程间通信的方式;其实也就是哪几种(我这里说的,是我的所谓的知道的。。。)事件,消息队列,信号量,条件变量(锁算不算?我只是认为是同步的一种);所以我们也就是要把这些掌握了,因为各有各的好处嘛;
条件变量我放到了上面的线程同步里面讲了,我总感觉这算是同步的一种,没有很多具体信息的沟通;同时吧,我认为条件变量比较重要,因为这种可以应用于线程池的操作上;所以比较重要;这里,抛开条件变量不谈,我们看看其他的东西;
1、消息队列:
queue 模块下提供了几个阻塞队列,这些队列主要用于实现线程通信。在 queue 模块下主要提供了三个类,分别代表三种队列,它们的主要区别就在于进队列、出队列的不同。

关于这三个队列类的简单介绍如下:
queue.Queue(maxsize=0):代表 FIFO(先进先出)的常规队列,maxsize 可以限制队列的大小。如果队列的大小达到队列的上限,就会加锁,再次加入元素时就会被阻塞,直到队列中的元素被消费。如果将 maxsize 设置为 0 或负数,则该队列的大小就是无限制的。
queue.LifoQueue(maxsize=0):代表 LIFO(后进先出)的队列,与 Queue 的区别就是出队列的顺序不同。
PriorityQueue(maxsize=0):代表优先级队列,优先级最小的元素先出队列。

这三个队列类的属性和方法基本相同, 它们都提供了如下属性和方法:
Queue.qsize():返回队列的实际大小,也就是该队列中包含几个元素。
Queue.empty():判断队列是否为空。
Queue.full():判断队列是否已满。
Queue.put(item, block=True, timeout=None):向队列中放入元素。如果队列己满,且 block 参数为 True(阻塞),当前线程被阻塞,timeout 指定阻塞时间,如果将 timeout 设置为 None,则代表一直阻塞,直到该队列的元素被消费;如果队列己满,且 block 参数为 False(不阻塞),则直接引发 queue.FULL 异常。
Queue.put_nowait(item):向队列中放入元素,不阻塞。相当于在上一个方法中将 block 参数设置为 False。
Queue.get(item, block=True, timeout=None):从队列中取出元素(消费元素)。如果队列已满,且 block 参数为 True(阻塞),当前线程被阻塞,timeout 指定阻塞时间,如果将 timeout 设置为 None,则代表一直阻塞,直到有元素被放入队列中; 如果队列己空,且 block 参数为 False(不阻塞),则直接引发 queue.EMPTY 异常。
Queue.get_nowait(item):从队列中取出元素,不阻塞。相当于在上一个方法中将 block 参数设置为 False。
其实我们想想,这个队列,是python进行封装的,那么我们可以用在线程间的通信;同时也是可以用做一个数据结构;先进先出就是队列,后进先出就是栈;我们用这个栈写个十进制转二进制的例子:

没毛病,可以正常的打印;其中需要注意的就是,maxsize在初始化的时候如果是0或者是个负数的话,那么就会是不限制大小;
那么其实我们想想,我们如果用做线程通信的话,我们两个线程,可以把队列设置为1的大小,如果是1对多,比如是创建者和消费者的关系,我们完全可以作为消息队列,比如说创建者一直在创建一些东西,然后放入到消息队列里面,然后供消费着使用;就是一个很好的例子;所以,其实说是消息队列,也就是队列,没差;
=====================================================================
下面来看一下事件
Event 是一种非常简单的线程通信机制,一个线程发出一个 Event,另一个线程可通过该 Event 被触发。

Event 本身管理一个内部旗标,程序可以通过 Event 的 set() 方法将该旗标设置为 True,也可以调用 clear() 方法将该旗标设置为 False。程序可以调用 wait() 方法来阻塞当前线程,直到 Event 的内部旗标被设置为 True。

Event 提供了如下方法:
is_set():该方法返回 Event 的内部旗标是否为True。
set():该方法将会把 Event 的内部旗标设置为 True,并唤醒所有处于等待状态的线程。
clear():该方法将 Event 的内部旗标设置为 False,通常接下来会调用 wait() 方法来阻塞当前线程。
wait(timeout=None):该方法会阻塞当前线程。
这里我想解释一下;其实对于事件来说,事件可以看成和条件变量是一样的,只是我们说说不一样的地方;
1、对于事件来说,一旦触发了事件,也就是说,一旦set为true了,那么就会一直为true,需要clear调内部的标志,才能继续wait;但是conditon不是,他是一次性的唤醒其他线程;
2、conditon自己带锁;事件呢?不是的;没有自己的锁;比如说有一个存钱的线程,有一个是取钱的线程;那么存钱的线程要存钱;需要怎么办呢?1、发现银行没有钱了(is_set判断);2、锁住银行;3、存钱;4、释放银行;5、唤醒事件;对于取钱的人;1、判断是否有钱;2、被唤醒了,然后锁住银行;3、开始取钱;4、清理告诉存钱的人,我没钱了(clear);5、释放锁;6、等着钱存进去;
其实说白了,就是记住一点;这个旗标需要自己clear就对了
写个例子,怕以后忘了怎么用;

其实时间和信号量比较像;但是信号量不用自己清除标志位;但是事件是需要的;

‘肆’ Python数据结构-队列与广度优先搜索(Queue)

队列(Queue) :简称为队,一种线性表数据结构,是一种只允许在表的一端进行插入操作,而在表的另一端进行删除操作的线性表。
我们把队列中允许插入的一端称为 “队尾(rear)” ;把允许删除的另一端称为 “队头(front)” 。当表中没有任何数据元素时,称之为 “空队”

广度优先搜索算法(Breadth First Search) :简称为 BFS,又译作宽度优先搜索 / 横向优先搜索。是一种用于遍历或搜索树或图的算法。该算法从根节点开始,沿着树的宽度遍历树或图的节点。如果所有节点均被访问,则算法中止。

广度优先遍历 类似于树的层次遍历过程 。呈现出一层一层向外扩张的特点。先看到的节点先访问,后看到的节点后访问。遍历到的节点顺序符合“先进先出”的特点,所以广度优先搜索可以通过“队列”来实现。

力扣933

游戏时,队首始终是持有薯仔的人
模拟游戏开始,队首的人出队,之后再到队尾(类似于循环队列)
传递了num次之后,将队首的人移除
如此反复,直到队列中剩余一人

多人共用一台打印机,采取“先到先服务”的队列策略来执行打印任务
需要解决的问题:1 打印系统的容量是多少?2 在能够接受的等待时间内,系统可容纳多少用户以多高的频率提交打印任务?

输入:abba
输出:False
思路:1 先将需要判定的词从队尾加入 deque; 2从两端同时移除字符并判断是否相同,直到deque中剩余0个(偶数)或1个字符(奇数)

内容参考: https://algo.itcharge.cn/04.%E9%98%9F%E5%88%97/01.%E9%98%9F%E5%88%97%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/01.%E9%98%9F%E5%88%97%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/

‘伍’ python生成多个队列

q=[]
foriinrange(9):
q.append(Queue())

‘陆’ python中栈和队列在功能上的区别

“栈”

“队列”
是数据结构,与具体的语言无关。
1.队列先进先出,栈先进后出。
2.
对插入和删除操作的"限定"。
栈是限定只能在表的一端进行插入和删除操作的线性表。
队列是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。
栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"
的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。
3.遍历数据速度不同。栈只能从头部取数据
也就最先放入的需要遍历整个栈最后才能取出来,而且在遍历数据的时候还得为数据开辟临时空间,保持数据在遍历前的一致性队列怎不同,他基于地址指针进行遍历,而且可以从头或尾部开始遍历,但不能同时遍历,无需开辟临时空间,因为在遍历的过程中不影像数据结构,速度要快的多
栈(stack)是限定只能在表的一端进行插入和删除操作的线性表。
队列(queue)是限定只能在表的一端进行插入和在另一端进行删除操作的线性表。
从"数据结构"的角度看,它们都是线性结构,即数据元素之间的关系相同。但它们是完全不同的数据类型。除了它们各自的基本操作集不同外,主要区别是对插入和删除操作的"限定"。
栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按"后进先出"的规则进行操作,而队列必须按"先进先出"的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。

‘柒’ Python 队列queue与多线程组合(生产者+消费者模式)

在线程世界⾥,⽣产者就是⽣产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果⽣产者处理速度很快,⽽消费者处理速度很慢,那么⽣产者就必须等待消费者处理完,才能继续⽣产数据。同样的道理,如果消费者的处理能⼒⼤于⽣产者,那么消费者就必须等待⽣产者。为了解决这个问题于是引⼊了⽣产者和消费者模式。

⽣产者消费者模式是通过⼀个容器来解决⽣产者和消费者的强耦合问题。⽣产者和消费者彼此之间不直接通讯,⽽通过阻塞队列来进⾏通讯,所以⽣产者⽣产完数据之后不⽤等待消费者处理,直接扔给阻塞队列,消费者不找⽣产者要数据,⽽是唯租直接从阻塞队列⾥取,阻塞队列就相当于⼀个缓冲区,平衡了⽣产者和消费者的处理能⼒。

比如,对于同时爬取多个网页的多线程爬虫,在某一时刻你可能无法保证他们在处理不同的网站,在某些时刻他们极有可能在处理相同的网站,这岂不浪费?为了解决这个问题,可以将不同网页的url放在queue中,然后多个线程来读取queue中的url进行解析处理,而queue只允许一次出一个,出一个少一个。相同网站上不同网页的url通常有某种规律,比如某个字段的数字加1,这种情况完全可以用这种模式,“生产者程序”负责根据规律把完整的url制作出来,再塞进queue里面(如果queue满了,则等待);“消费者程序(网页解析程序)”从queue的后面答团挨个取出url进行解析(如果queue里面是空的,则等待),即使是多线程也能保证每个线程得到的是不同的url。这个过程中,生产者和消费彼此互不干涉。

下面以实例说明如何将queue与多线程相结合形成所谓的“ 生产者+消费者 ”模式,同时解决 多线程如何退出 的问题(注意下例中是“一个生产者+多个消费者”的形式,多生产者+多消费者的模式可在此基础上进一步实现):

上述程序的过程如下图:

注意
(1)上述程序中生产者插入queue的时间间隔为0.1s,而消费者的取出时间间隔为2s,显然消费速度不如生产速度,一开始queue是空的,一段时间后queue就变满了,输出结果正说明了这一点。如果将两个时间调换,则结果相反,queue永远不会满,甚至只有1个值,因为只要进去就被消费了。
(2)消费者程序是通过“while”来推动不断执行的,何时结束?上例中通过在queue中增加None的形式告诉消费者,生产者已经结束了,消费者也可以结束了。但消费者有多个,到底由哪个消费者得到None?为解决这个问题,上例中在消费者中先判断当前取出的是不是None,如果是,则先在queue里插入一个None,然后再break当前这个消费者线程,最后的结果是所有的消费者线程都退出了,但queue中还剩下None没有被取出。因此在程序的后面增加了一个for循环来挨个把queue中的元素取出,否则最后的q.join()将永远阻塞,程序无法往下执行。
(3)程序中每一个q.get()后面都跟有一个q.task_done(),其作用指举兆是从queue中取出一个元素就给q.join()发送一个信息,否则q.join()将永远处于阻塞状态,直到所有queue元素都被取出。

多线程“生产者-消费者”模式一般性结构图

阅读全文

与python队列类相关的资料

热点内容
如何用电脑解压缩文件 浏览:444
pubg用什么服务器 浏览:526
田汉pdf 浏览:661
记录仪如何安装安卓系统 浏览:594
python求灰度均值 浏览:756
c编译器是系统软件吗 浏览:694
获取服务器内网地址 浏览:536
新手妈妈如何带新生儿APP 浏览:157
java日程管理 浏览:376
高清视频链接加密 浏览:407
新买的阿里云服务器怎么配置 浏览:612
在线编译器为什么刷新还在 浏览:212
云服务器系统盘可以装数据库 浏览:906
php绘制图形 浏览:588
支付服务器异常怎么办 浏览:76
java拨号 浏览:868
er5200如何设置虚拟服务器 浏览:572
网络中心服务器叫什么 浏览:459
isplay单片机下载器 浏览:482
怎么查看服务器地址和端口 浏览:187