悠然乱弹:关于优先队列

背景分析

说到优先队列,熟悉jdk的朋友可能就知道,从jdk1.5开始,jdk中就提供了优先队列类,具体的做法就是实现了可比较的接口之后,就可以过比较使得优先级高的对象先出队列,从而体现“优先”性。

一般的情况下,这么做当然也都是没有问题的。

我们假设现在有这么一个应用场景:

你到银行去办一项业务,但是由于办业务的人多,由于金卡,银卡,钻石卡的用户不停的来,这样队列中的普通用户们就一直没有办理业务的机会。你和其它的普通用户的怒火一点一点的升起来,最后小宇宙爆发,估计够大堂经理受的。同样,如果今天如果来的都是钻石卡用户,那些金卡同志们也会一直没有机会输业务,他们同样会小宇宙爆发的。

OK,我们再来假设另外一个场景。比如在证券交易所,有些交易用户是大客户,一般来说,大客户享受有更好的交易条件,假设我们制订一个规则,就是帐户金额(单位万元)取log10之后,即为其优先级。

假设有一天交易量远远超过计算机的处理能力,结果就会发现,小散们几乎没有交易机会。反过来又影响了大客户们的利益。最后所有的客户都不满意:大客户想买/卖小散们的单,小散们由于优先级太低,根本没有机会交易。最后就表现为撮合效率非常低,客户满意度同样非常低。

OK,通过上面的两个场景,就会发现我们简单的利用优先队列来处理有优先级的问题,实际上在许多场景下是不合理或不现实的。

这个时候必须给出可行的解决方案,即体现高端客户的优先权,又要照顾到低优先级别的用户的权利,给他们也有充分的执行机会,两者需要兼顾。

解决方案

上一节,有说到,常用优先队列在解决上面的问题的时候,就会有问题,高者恒高,低者恒低导致所有参与者与管理者都不希望出现的情况。这个时候矛盾就很难调和了,用优先队列吧,有上面说的问题;不用优先队列吧,又体现不出差异化服务--差异化服务本身不是目的,差异化服务看中的是客户兜兜里的真金白银才是真的。

因此解决方案就要既照顾到高优先级的优先权,也照顾给优先级者以阳光普照。这个时候,高优先级者非常开心,因为他花钱了,买到了优先服务的权利,低优先级的用户虽然慢了点,但是服务还是可用的==这个时候这些用户无法识别自己被给予了二等公民待遇,但是考虑到自己在用免费服务或者自己的存款很少等,也就可以接受。最近一段时间滴滴和快滴明显就有这个问题,所有的出租车都去抢在线叫单(高优先级),导致许多不用滴滴和快滴的用户(低优先级)叫不到车,从而引发了许多人的批评。

那也这个时候,可以给出一个方案,那就是优先级提升方案,即在一定条件下触发一个策略计算器,对系统中的用户的优先级进行提升。

这样,随着任务的等级不断的提升,总是可以升级到最高级的,这样就肯定有执行机会了。当然,由于低优先级的人离最高等级有点远,因此升级时间会比较长。

于是马上行动,编写优先级提升算法,改完一执行,效率那是相当的低,把大量的时间都花到优先级提升上了。所以,理想是丰满的,现实是骨感的这句话又得到了验证。

创建具有16个元素的优先队列数组,分别对应0-15共16级的优先队列,新任务到来时,根据优先级,分别添加到对应优先级的队列末尾,任务处理线程会不断从高优先级到低优先级扫描,找到第一个需要处理的任务,并进行处理。另外,每次处理一个业务,会把所有的任务请求的延迟计数器加1,如果延迟计数器达到某一设定值,则提高其优先级,以避免在高优先级任务多时,低优先级请求一直得不到处理的情况发生。

问题:因为一般情况下大多数,低优先级的任务远多于高优先级的任务,因此,在查找第一个任务时,需要做一个循环对优先队列数据进行遍历,并确定队列是否为空,直到找到一个存在的任务或发现所有的队列为空。如果找到了需要处理的任务,还要对所有的低优先级任务的延迟计数器加1,并把达到提升优先级的任务进行优先级提升。

存在的问题

在没有任务时,对优先队列数组进行空转;在高优先级任务较少时,有大量的优先队列计数器加1操作及,优先级提升操作,对系统的性能影响较大。

优化方案

主要进行了三个方面的改进进:
1. 对优先队列数据结构进行调整
考虑到处理一个任务请求的时间远大于添加一个任务请求到队列的时间,因此增加一个时间段的概念,即把一个任务处理周期内的同一优先级的任务作为一个优先级提升单位。即如果需要增加延迟计数器或提升优先级,则一同进行操作,这样就把每一个元素都需要进行的操作变成了一组任务请求共同操作,大大减少了处理量。设处理周期时间段平均任务数为n,则可以节省(n-1)的计数器加 和优先级提升的时间。
2. 对优先级提升级别进行限制
为了便于高优先级的绝对处理,避免大量低优先任务请求升到高优先级后影响到高优先级任务的处理,因此可以保留几个高优先级别,不允许进行任务提升。
3. 对提取任务请求进行优化
原有的轮询方式在任务较少或高优先级任务较少时,会导致大量的无用判断,消耗了大量的CPU,因此,增加了一个请求队列指针,指向一个具有最高优先级的时间片段请求队列的队头。如果为空,则表示没有任务请求,否则直接提取任务进行处理即可。通过此优化把轮讯任务的时间减少到无。

总结

通过以上优化,可以大大优化优先队列的处理性能,同时又提供了高级特性满足一些高级应用需求。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值