2019/11/04 02-Queue使用和分发器实现

在这里插入图片描述在这里插入图片描述
消息中间件也称消息队列,本质上是排个队,数据还是先进先出,消息队列整体完成功能,1.解耦,2.缓冲(最重要的两点,当然还有其他的),生产中遇到的问题就拿这个解决就行

python中的消息队列,queue模块,是解决线程问题的,如果是服务,跨进程的跨网络的,就需要用第三方的
queue必须掌握

在这里插入图片描述
多进程在这里插入图片描述
需要用多线程版本的,queue模块实现了生产者消费者使用的队列在这里插入图片描述
lifequeue,是后进先出(栈),FIFO先进先出在这里插入图片描述
、是后进先出(栈)在这里插入图片描述
优先队列
在这里插入图片描述
最大size=0,代表实际上是可以给一个上线的在这里插入图片描述在这里插入图片描述
主要用的方法就是get和put在这里插入图片描述
里面是空的,empty’
在这里插入图片描述
没有上限就不可能撑爆
在这里插入图片描述
queue常用的两个方法是get和put,put是提交数据,get是拿数据回来
它是把列表的引用地址塞进去了

在这里插入图片描述在这里插入图片描述
hex16进制
在这里插入图片描述
queue是不支持索引的
队列虽然看起来像列表但是往往不想让你支持中间插来插去的,中间插入引起整个数据挪动,这种交给列表吧,队列一般是先进先出,后进先出,队列操作的主要是两头,所以根本就没有必要提供索引,队列的解决方式就决定了不要提供索引,无非就是type,要么就是queue
默认的queue是先进先出

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
get了最后一个,就已经是为空了
在这里插入图片描述
queue刚创建是空的,现在程序就卡住了,就阻塞了,结束不了了
在这里插入图片描述
当queue空的时候,调用就会阻塞,阻塞的时候相当于主线程和我们是交互的,主线程卡住,就交互不了了

block是一块,拿一块东西阻塞在那,block=true默认就是阻塞行为
timeout=none等多久超时,超过这个时间就不等了,none就是永久等待

在这里插入图片描述
改成5秒试试,到5秒就报错了,拿到一个空的异常
在这里插入图片描述
empty会返回异常,这个异常定义在queue中
在这里插入图片描述
设定满了还往里面放数据就会报错
在这里插入图片描述
再put进去一个数据
在这里插入图片描述
现在就不是empty了
在这里插入图片描述
用不阻塞的方式拿就拿到了,如果没有数据的时候,用get方法,默认行为是阻塞的,非阻塞就会立即返回数据,get就是拿
在这里插入图片描述
再次拿就是空了,只要拿不到对于不阻塞行为,就抛出一个异常,只要get没拿到要么抛出异常,要么就死死的等,相当于永久阻塞
在这里插入图片描述
永久阻塞相当于如下,一直等到里面有数据未知
在这里插入图片描述
下面是5秒等,5秒内有数据来就ok,超过5秒没数据就报错了,
在这里插入图片描述
如果有数据就拿走,无数据也不会等,因为你写了不等
在这里插入图片描述
**不等5秒,直接报错 **
在这里插入图片描述
说不等,写5秒就没有意义
在这里插入图片描述
傻傻等和只等5秒
在这里插入图片描述
根本不等,等几秒也没用
对于返回的结果来看,get方法要么一直在等,要么就是等一会或者根本就不等
从拿到结果来看,要么真正拿到你想要的数据,要么直接抛出异常

在这里插入图片描述
有数据则拿,无数据则抛异常
在这里插入图片描述
在给定的时间内,要么拿到数据,要么在时间结束后直接抛出异常
在这里插入图片描述
这个不会抛出异常,这是一直等
在这里插入图片描述
还有一个方法,nowait不等超时时间,就直接报错
在这里插入图片描述
nowait没有参数,因为get里面(false)写了跟没写一样
在这里插入图片描述
现阶段用get的阻塞行为,如果用nowait还要处理异常问题,还是 一直等,等到有数据为止,但是可以选择不等,选择处理不等就要选择不同的处理方案
不等有可能没拿到数据,处理方案就要变化。,等 和不等要不同的处理方案代码,就要用阻塞行为

在这里插入图片描述
什么动能放,因为放的是内存引用地址
block=true是一种阻塞行为,没有体现的原因是没有上线,所以塞数据可以一直塞
在这里插入图片描述
inpit是阻塞的等你输入,range对象算一个塞进去,引用地址
在这里插入图片描述在这里插入图片描述
现在传入数据
在这里插入图片描述
一条波浪线代表卡住了,再敲任何数都无效,阻塞住了,已经是full了
在这里插入图片描述
已经添加5个,full就是true了,卡住了在这里插入图片描述
nowait代表不等
如果为空不进来,就不会产生阻塞行为,不为full添加数据
在这里插入图片描述
如果用了get,超时和阻塞都有效果,指的是在超时时间内能不能完成,一个抛出full,一个抛出空empty,这两个方法都是有异常产生的,工作没有成功完成都会抛出异常
get方法如果没有成功拿到数据就要抛出异常,空,put方法把数据提交上去,只要不提交成功 就一定返回一个异常,这个异常就是full异常,满 了,如果在规定时间内,把数据提交进去就正常,否则如果是永久阻塞就一直等,等到空的适合就把数据加进去

lifoqueue也是一样的
queue.qsize(),qisize就是队列size,如果发现size大于0(不能保证get的适合不阻塞),感觉上是元素,看到qsize有数据也不不能保证get
虽然当下看到queue大于0 ,真的去拿的适合,不能保证拿的适合还有

在这里插入图片描述
数据只能消费一次,一旦有人消费掉了,其他就不能再消费了在这里插入图片描述
如果1想要给两个都使用,
在这里插入图片描述
如果想这么做,只能各给各的,速度就可以不一样在这里插入图片描述
get方法和put方法都要完成自己的工作,如果完成不来就一定会抛出异常,如果不完成永久等待,就一直等待下去,如果超时或者阻塞就死等
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
生产者要生产数据,中间加队列,生产的数据也可以称为消息
拿到日志,把日志加载起来,加载起来读一行行,一列列读取,交给滑动窗口进行分析处理,处理的时候,对于数据源来讲需要跟多个消费源进行数据处理

每个消费者都希望拿到相同的数据,

分发给不同的handler,不同的handler做不同的事情,用的是同一份数据

在这里插入图片描述
如何分发就是用轮询策略
每一个handler处理的数据应该是相同的,不能说a拿到了数据,b就拿不到,做平均值,a拿到 了,b就拿不到了,这样就不准了,所以要求handler a和b都应该拿到相同的数据
虽然采用轮询策略是最简单的,但是轮询的时候 ,数据是一对多的策略,同一份数据给多个handler是一致的
但是我们的queue不支持
只能拿一次,a拿走,b就看不到了,需要想办法解决

在这里插入图片描述
每个消费者自己配一个queue,把数据分别塞到queue里,每个消费者自己用一个queue相对比较容易
在这里插入图片描述在这里插入图片描述
**线程 threading模块,非常常用 的,还有一套方案是协程,是异步的,现在写的程序多数跑的是函数,从第几行第几行封装起来就是函数,是你应该做的事情 **

线程的目标函数是谁,启动起来传什么参数(4,5)
这里返回一个线程对象,
在这里插入图片描述
要使用,必须启动一下

红蓝分支,蓝色走到那里睡着了,对于红色的线程继续向下走
等蓝色醒来,把9输出,双==打完

在这里插入图片描述
运行这个模块的线程叫主线程,一个分支休息了,之后继续也走完了,两个都没事干就主线程结束了
在这里插入图片描述
这有什么好处
input按照道理是要阻塞的,等着你输入
在这里插入图片描述
一个工作模式下,有一个线程没结束大家都不结束在这里插入图片描述
按照现在这么写这个程序就不会退出
在这里插入图片描述
现在用这个之前的函数,注册一些东西在这里插入图片描述在这里插入图片描述
写一个分发器,注册的时候需要告诉数据是谁,怎么处理handller,width,interval

在这里插入图片描述
下面这个函数交给线程来运行就卡住 了,现在两个地方都会卡出,会不会互相影响在这里插入图片描述在这里插入图片描述
这两个地方都卡住了,但是get没有什么体现,只是在另一个线程等你

在这里插入图片描述
输入1以后,就能get到值,就不卡住了在这里插入图片描述
点击中止,非正常结束,返回的是1
在这里插入图片描述
导入线程模块
在这里插入图片描述
想放些数据到queue里去在这里插入图片描述
这里使用queue不用生成器了,现在的queue是阻塞的了在这里插入图片描述
现在把这些函数放到一个线程里执行,q.get是空就卡住了,不影响下面的主线程在这里插入图片描述
上面的卡住不会对下面有影响
在这里插入图片描述
函数可以在不同线程里调用,运行的不是同一个栈,函数的栈跟线程相关,同一个函数在不同的线程调用,压的不是同一个栈,同一个函数在不同栈上跑,是各自定义各自的
在这里插入图片描述
为了运行起来加几个东西,handler,queues,虽然放的是线程对象,但是里面放的是不同的handler(定义同一份,实际各是各的)
在这里插入图片描述
可以从src拿到一个数据,handler消费的是buf里的,本质上数据来自于queue,各是各的queue,所以在queues遍历,把数据put即可
线注册很多queuqe,把queue作为数据源交给window,windows函数去执行调用queue,queue里面拿到数据后,最后拿到一定程度后,交给handler处理,所以handler本周四行数据来自于queue,所以只要往queue里扔数据即可

开启线程等待数据,所以下面就需要死循环加入数据
在这里插入图片描述
整个source可以源源不断产生数据
在这里插入图片描述
这里相当于源源不断从数据拿源拿数据,src=前面定义的是s=source(),传进来即可在这里插入图片描述
攒一批够了就要进行handler处理在这里插入图片描述
用多线程的意思就是get的时候会阻塞,阻塞的时候抛到线程里去在这里插入图片描述
主线程里面,run函数,run函数里面就在分发给AB两个线程,跑window函数,然后get方法,等run给两个数据
qA和qB是给线程用的,都阻塞,但是run还在运行,就把数据给A和B,有数据就不阻塞 了,get后继续向下执行,再回头get
这就是并发
在这里插入图片描述
生产者是run函数,消费者是window函数,这两个不会直接调用,是把数据打入queue,window自己使用,这就是解耦,但是生产环境未必产生的日志用生成器,所以中间必须有个queue,这样可以先把数据放到queue里,不直接交给消费者,消费者做分析一般是比较慢的在这里插入图片描述
run先把线程起来,然后把数据发送在这里插入图片描述在这里插入图片描述
下面只要修改数据源,从日志里提取,用轮询的方式送到queue里去
在这里插入图片描述
改成avg,首先会注册在这里插入图片描述
注册只是把queue放到列表里去
t建立一个线程 ,线程不启动,只是把对象保存到handler里面去,然后把queues》append和handlers.append保存好,以备后用
在这里插入图片描述
如果要启动,就在线程里启动window函数,也就是有个线程里跑window函数,相当于自己调用,只不过是用线程调用在这里插入图片描述
函数跑起来就会卡在get这里等待在这里插入图片描述
在这里拿到数据
在这里插入图片描述
这里判断攒够了就去计算一下在这里插入图片描述
报错,应该是,时间不能减去整型,时间应该跟某一个timedelta类型相减在这里插入图片描述
这里需要修改
在这里插入图片描述这个数据源就是从我们生成的
在这里插入图片描述
打印其实是在window,线程里打印的,看清楚一点,这个就是当前线程在这里插入图片描述
window函数加一句,比较一下两个线程的区别在这里插入图片描述在这里插入图片描述
run里面是死循环,死循环不结束,下面就不执行
在这里插入图片描述
提上去即可,不是同一个线程
在这里插入图片描述
通过这样的改造实现了数据的分发过程,拿到数据怎么提交给线程,使用的读取方式是一种阻塞行为,只能用多线程来解决,把数据获取方式用线程来做
在这里插入图片描述
window在线程跑了,函数定义同一个,函数调用里,执行了handler,每一次调用其实都不一样,就算再同一个handler里,两次调用也都不一样
函数的每一次调用都是不同的,每一次都是压栈,每次局部变量都是不同的,都在自己的栈上

在这里插入图片描述在这里插入图片描述
一个全局一个局部,每次都要重新创建,局部变量是在栈上重新创建的,local,函数调用每次都要重新创建在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值