前言:
我刚接触消息队列时,也是在网上百度搜索,发现好多博客写的有关消息队列Queue的时候,写的例子里都有多线程或者多进程的内容,把这些内容和Queue写在一起,我感觉如果是新手的话,是不太好理解的;因为从性能优化的角度来讲,消息队列也是为了分配任务,避免大量的并发请求过多过快的消耗服务器资源,从而优化产品的性能,这样的话,多线程或者多进程,又或者协程等等都是可以达到优化的目的,所以,我觉得在讲消息队列的内容时候,对于新手,还是不要涉及其他的内容比较好;
在练习Queue的知识点时,我也有犯过些错误,比如说看了别人的博客,最后也实现了自己想要的效果,但是最后才反应过来,我写的代码,其实没有Queue也可以的,完全可以用Thread多线程来实现,而Queue的知识可以说是没有练习到,这也是我说上面一段话的背景;
多线程和消息队列有什么相同和不同?
相同点:都可以作为优化系统性能的方案;
不同点:两者优化性能的方式不同,打个比方如下:
1.比如用户访问登录接口,那么很多个用户同时访问该接口时,后台可以同一时刻为每一个用户单独起一个线程,让用户在最短时间内拿到登录结果,这也叫用户并发登录,这样对用户来说体验会好些,但是对系统来说,就很消耗资源,容易崩溃,这种场景用多线程比较合适(实际企业这样用的不多);
2.再比如,测试人员经常要运行自动化案例,有时运行几个小时都结束不了,而且测试化境很复杂不好搭建,不能提拱并发执行,这时,可以考虑用消息队列了,每个人都可以在下班前提交一个测试任务,先提交的任务先运行,按顺序执行任务,等上一个测试任务执行完,再执行下一个的任务,像这种不要求立刻得到结果的场景,就可以考虑用消息队列了,说到这里,如果有需要了解学习自动化测试平台开发的小伙伴,欢迎和我交流,可以搜索并关注公众号“测试运维”,一起进步!
3.最后,再打个比方来说明消息队列和多线程的区别,比如地铁站怎么处理客流高峰呢?一种方案是临时增加很多个刷卡通道并同时开放,使每个通道排队等候的人不多,这种方案可以让乘客很快进站,类似于多线程,这种方案对乘客来说是好事,减少了乘客的等待时间,但是对于地铁站来说就很难了,因为地铁站就那么大,不是想开几个通道就开几个,虽然技术上可以实现,但是不太现实;另一种方案,保持原有的刷卡通道个数不变,组织乘客排队刷卡进站,哪怕队已经排的很长很长,拐着弯排队,甚至是排到地铁站外面,只要大家都有序排队,最后都可以进站,这个方案就是类似消息队列,在队列管控上做改动,而不是在基础硬件设施上做改动,这种方案,对地铁站来说是好事,不用额外新建那么多通道,但是对乘客来说,等待的时间太长,体验不好;
一.先源码实现一下queue,参考网上的。
class Queue(object):
def __init__(self, max_item):
self.queue = []
self.max_item = max_item
def enqueue(self, item):
for i in item:
if len(self.queue) >= self.max_item:
print('队列已满')
return self.queue
else:
self.queue.append(i)
return self.queue
def dequeue(self):
return self.queue.pop(0)
def is_empty(self):
return self.queue == []
def is_full(self):
return len(self.queue) >= self.max_item
def size(self):
return len(self.queue)
if __name__ == '__main__':
queue = Queue(3)
print(queue.enqueue([1,2,3,4])) #队列已满,[1, 2, 3]
# print(queue.dequeue())
print(queue.is_full())
二,Python内置的四种队列的类型 (本次写的是LILO)
- LILO
先进先出,只能在尾部插入元素,只能从头部取出元素 - LIFO
先进后出,类似栈 - 优先队列
队列元素为元组类型,即(优先级,数据)。 - 双端队列
三.常用的方法
-
q.task_done() 需要结合q.join来用,具体如下:
1.如果用了q.join(),那就一定要通过写q.task_done() ,来通知q.join当前事件已完成, 不写q.task_done()的话,q.join收不到当前事件完成时的信号,还会阻塞在q.join执行的地方等待接收信号,join后的代码得不到正常执行;
2. 同时不写q.join,和q.task_done() ,也是可以的,可以正常执行;
3. 只写q.task_done()不写q.join也是可以的,可以正常执行;
-
q.join() 直到queue队列中的所有事件都处理完毕,队列为空以后再执行q.join()之后的代码,如果用了q.join(),那就一定要写q.task_done()
-
q.put(item[, block[, timeout]]) 向队列中增加事件, .可以利用put和get进行传参, #注意这里如果有多个参数,要用键值对或字典
- q.get( block[, timeout]]) 执行队列中的事件,执行完后将该事件从队列中删除,并返回当前的事件
-
q.qsize() 返回队列的大小
-
q.empty() 如果队列为空,返回True,反之False
- q.full() 如果队列满了,返回True,反之False,Queue.full 与 maxsize 大小对应
- q.get_nowait() 相当于Queue.get(False),非阻塞方法
- q.queue 返回当前队列中所有的任务
四. 一些需要注意的细节
入队列时堵塞
from queue import Queue
- 入队列非堵塞
try:
- 出队列堵塞
- 出队列非堵塞
- 设置超时
from queue import Queue