你的电梯,我的电梯,大家的电梯

你的电梯,我的电梯,大家的电梯_第1张图片

目录
  • 调度算法们
    • 传统电梯调度算法
      • 先来先服务算法(FCFS)
      • 最短寻找楼层时间优先算法(SSTF)
      • 扫描算法(SCAN)
      • LOOK 算法
      • SATF 算法
      • ALS算法
    • 实时电梯调度算法
      • 最早截止期优先调度算法
      • SCAN-EDF 算法
      • PI 算法
      • FD-SCAN 算法
    • 群控电梯调度算法
      • 最短距离调度(THV)
      • 最小最大请求分配(MIN-MAX)
      • 高级交通管理决策(ATM)
      • 最小成本调度(COST)
      • 更现代手段
    • 参考
  • 我们作业的电梯
    • 背景
    • 当电梯没有三六九等
      • 我的策略
      • 别人的策略
    • 当电梯们不再相同
      • 进入划分
      • 过程中划分
    • 结语

"每个程序员看见电梯,都会想电梯的调度算法怎么这么蠢"

调度算法们

传统电梯调度算法

先来先服务算法(FCFS)

先来先服务(FCFS-First Come First Serve)算法,是一种随即服务算法,它不仅仅没有对寻找楼层进行优化,也没有实时性的特征,它是一种最简单的电梯调度算法。
它根据乘客请求乘坐电梯的先后次序进行调度。此算法的优点是公平、简单,且每个乘客的请求都能依次地得到处理,不会出现某一乘客的请求长期得不到满足的情况。
这种方法在载荷较轻松的环境下,性能尚可接受,但是在载荷较大的情况下,这种算法的性能就会严重下降,甚至恶化。
人们之所以研究这种在载荷较大的情况下几乎不可用的算法,有两个原因:
任何调度算法在请求队列长度为1时,请求速率极低或相邻请求的间隔为无穷大时使用先来先服务算法既对调度效率不会产生影响,而且实现这种算法极其简单。
先来先服务算法可以作为衡量其他算法的标准。

最短寻找楼层时间优先算法(SSTF)

最短寻找楼层时间优先(SSTF-Shortest Seek Time First)算法,它注重电梯寻找楼层的优化。
最短寻找楼层时间优先算法选择下一个服务对象的原则是最短寻找楼层的时间。
这样请求队列中距当前能够最先到达的楼层的请求信号就是下一个服务对象。
在重载荷的情况下,最短寻找楼层时间优先算法的平均响应时间较短,但响应时间的方差较大,原因是队列中的某些请求可能长时间得不到响应,出现所谓的“饿死”现象。

扫描算法(SCAN)

扫描算法(SCAN) 是一种按照楼层顺序依次服务请求,它让电梯在最底层和最顶层之间连续往返运行,在运行过程中响应处在于电梯运行方向相同的各楼层上的请求。
它进行寻找楼层的优化,效率比较高,但它是一个非实时算法。扫描算法较好地解决了电梯移动的问题,在这个算法中,每个电梯响应乘客请求使乘客获得服务的次序是由其发出请求的乘客的位置与当前电梯位置之间的距离来决定的。
所有的与电梯运行方向相同的乘客的请求在一次电向上运行或向下运行的过程中完成,免去了电梯频繁的来回移动。
扫描算法的平均响应时间比最短寻找楼层时间优先算法长,但是响应时间方差比最短寻找楼层时间优先算法小,从统计学角度来讲,扫描算法要比最短寻找楼层时间优先算法稳定。

LOOK 算法

LOOK 算法是扫描算法(SCAN)的一种改进。对LOOK算法而言,电梯同样在最底层和最顶层之间运行。
但当 LOOK 算法发现电梯所移动的方向上不再有请求时立即改变运行方向,而扫描算法则需要移动到最底层或者最顶层时才改变运行方向。

SATF 算法

SATF(Shortest Access Time First)算法与 SSTF 算法的思想类似,唯一的区别就是 SATF 算法将 SSTF 算法中的寻找楼层时间改成了访问时间。
这是因为电梯技术发展到今天,寻找楼层的时间已经有了很大地改进,但是电梯的运行当中等待乘客上梯时间却不是人为可以控制。
SATF 算法考虑到了电梯运行过程中乘客上梯时间的影响。

ALS算法

此算法主要特点是把请求分为主请求和可稍带请求。在执行主请求时把所有能捎带的亲求都带上。
怎么确定哪个是主请求就仁者见仁了。

实时电梯调度算法

最早截止期优先调度算法

最早截止期优先(EDF-Earliest Deadline First)调度算法是最简单的实时电梯调度算法,它的缺点就是造成电梯任意地寻找楼层,导致极低的电梯吞吐率。
它与 FCFS 调度算法类似,EDF 算法是电梯实时调度算法中最简单的调度算法。
它响应请求队列中时限最早的请求,是其它实时电梯调度算法性能衡量的基准和特例。

SCAN-EDF 算法

SCAN-EDF 算法是 SCAN 算法和 EDF 算法相结合的产物。SCAN-EDF 算法先按照 EDF 算法选择请求列队中哪一个是下一个服务对象,而对于具有相同时限的请求,则按照 SCAN 算法服务每一个请求。它的效率取决于有相同 deadline 的数目,因而效率是有限的。

PI 算法

PI(Priority Inversion)算法将请求队列中的请求分成两个优先级,它首先保证高优先级队列中的请求得到及时响应,再搞优先级队列为空的情况下在相应地优先级队列中的请求。

FD-SCAN 算法

FD-SCAN(Feasible Deadline SCAN)算法首先从请求队列中找出时限最早、从当前位置开始移动又可以买足其时限要求的请求,作为下一次 SCAN 的方向。
并在电梯所在楼层向该请求信号运行的过程中响应处在与电梯运行方向相同且电梯可以经过的请求信号。
这种算法忽略了用 SCAN 算法相应其它请求的开销,因此并不能确保服务对象时限最终得到满足。

群控电梯调度算法

最短距离调度(THV)

这是最简单的调度算法,其根据轿厢所在楼层与请求所在地的相对位置按一定规定计算出来该请求的适应值FS作为评价函数,评价出来最合适的电梯来服务该请求。
FS到底怎样计算就是个“玄学”的事情了。你可以简单到直接用楼层差,也可以考虑到电梯有上下行的不同把线性的楼层看作环形——事实上后者更为合理。

最小最大请求分配(MIN-MAX)

该方法的思路是把发出请求时所反映的客运需要量的微小变化看成是对整个电梯群需要量的变化加以控制。它根据请求和电梯数量等状态矢量,预测候梯时间,把预测的候梯时间最大值作为评定函数,用该值最小的电梯来服务请求。

高级交通管理决策(ATM)

此方法结合了最短距离调度和负载均衡。

最小成本调度(COST)

略,可参考链接。

更现代手段

群控电梯调度总体来说就是运用函数算一算每个电梯和每个请求的合适程度,那么这个函数怎么设计就可以开脑洞了,万一可以用机器学习拟合一个……

参考

电梯群控系统各种策略的分析比较
我猜,每个程序员对着电梯都想过调度算法吧!


我们作业的电梯

背景

这是BUAA的OO课程的三次作业,不那么仿真地模拟了目的选层电梯的调度。
第一次作业是单电梯不限人数;
第二次作业是多电梯限制承载人数;
第三次作业实现了动态增加电梯、电梯分种类(运行速度、停靠楼层不同)运行。

当电梯没有三六九等

这里指的是前两次作业,每个电梯能干的事情都是一致的。
其实各种调度策略是真真正正的各有优劣。自己写的测评机顺带监测了大概7套程序(互测里)的同种输入的运行时间……总体来说,平均下来只有1个程序明显慢于其他程序,其他则是不分伯仲;而每个程序都有第一个执行结束的时候——即便是那个平均下来最慢的程序也会有几次战胜其他程序的时候。

我的策略

如果真的要套用前述的各种策略的话,我的应该算是ALS。
第一次作业单电梯,主要谈谈设置主请求。第一个到的请求必然是主请求,但等待队列不是空的时候,就要找一下哪个请求可以在过程中捎带更多人了——譬如电梯决定向下运行时,会从顶层向下找第一个要下楼的人作为主请求。
第二次作业对于每个电梯自己来说,其行为和第一作业一致。但是增加了一个分派请求的中央控制器,把请求分给每个电梯。中央调度器的策略大概是前面说的ATM。但事后想一想,反正请求产生是随机的……如果只在请求初次进入时候来分派此请求,而不是在每次有请求进入时候重新分派所有请求,那运用ATM策略和直接随机分配或是顺序分配的话,电梯的性能变化应该不会很大。
想都可以想,但想要保住正确性的分,还是不浪了……

别人的策略

  • 单电梯
    最显眼的应该是SCAN了,因为它即使没有请求也在“瞎跑”,输出比其他人长很多。意外的是这种电梯性能有点高……不过个人认为是数据量不够大,足够大的话SCAN性能至少应该比不过LOOK。
    LOOK是我周围人用的最多的,各个都号称自己魔改了LOOK,实际怎么改的我也没听懂不过测试出来性能不错。
    ALS是课程组作为基准的算法。但是ALS也有很多写法……主请求设置不好电梯会特别傻……

  • 多电梯
    主要就是两派了:自由竞争和统一分派。

    • 自由竞争
      很直接,来了一个请求,所有电梯上去抢,谁抢到了是谁的。所以它有个更响亮的名字:“饿虎扑食”。
    • 统一分派
      这和我的思路一样,进来以后用中央控制器分派请求给电梯,每个电梯只能看见自己被分派的请求,对其他请求一无所知。

    单就性能来看,两者真的不分伯仲,写好了的话强测都在98以上。但自由竞争似乎要注意一下扑空了时候的情况,分派则要好好想一想怎么平衡负载。

当电梯们不再相同

其实,一个人能不能乘坐一种电梯的判断很容易。所以个人把本次作业和前几次的最大差异设定为如何对请求进行划分——即如何处理换乘问题。

进入划分

当一个请求到达时,便对其进行划分,分为可以被单一电梯服务的多个请求。

  • 静态划分
    也就是预设好的划分,譬如从3层到15层永远划分成3—4和4-15,不考虑划分成3-5和5-15等其他情况。
    这样做逻辑更加简洁,每一种请求会划分的情况都是固定的,可能对于debug更为有利。
    当然静态划分也可以再细分。
    ---尽可能少换乘
    ---分区多换乘
    可能有人会不能理解多换乘的意义。但实际上,我们考虑一类电梯处于高峰期,相比之下其他电梯都比较空闲,多换乘的划分可以充分调用各个电梯。
    比如这次作业的电梯的停靠楼层:
    ---A:-3 ~ 1,15 ~ 20;
    ---B:-2 ~ 1,2,4,5 ~ 15;
    ---C:1,3,5,7,9,11,13,15;
    我自己的程序在划分请求时,会按段分割:-3 ~ -2,-2 ~ 1,1 ~ 5,5 ~ 15,15 ~ 20。
    这样显然可能会让一个本来只需要乘坐一种电梯的乘客进行不必要的换乘。
    但假设同一时间有超过A电梯人数上限的人要从1层到20层,多换乘的划分就可以有效的使B和C运行起来解决把人从1送到15层的问题。可以预见这样会提高效率。
    当然也要考虑到电梯“空”开门的情况——停靠但无人上下。这部分本人没有优化,毕竟正确性要紧……
    (事实上,多换乘在应对更多请求时,性能应当比少换乘性能好。即使存在空开门问题,我的程序在强测过的为数不多的点中有3个点达到了99,强行送自己进了互测……虽然比不过其他能拿一堆100的DaLao就是了)
  • 动态划分
    考虑到每个时刻电梯的运行情况,同一种请求的换乘策略可能不同。
    这理论上可以解决静态划分的多种痛点……难就难在我没想好怎么保证程序的简洁性(其实我是不想重构)。

过程中划分

请求进入时不划分,通过电梯把请求者送到目的楼层或是离目的楼层最近的楼层,请求者走出电梯时候判断是否到达目的地,不是的话进行新一轮请求。
也就是请求在被电梯服务过一次后再考虑要不要划分。其实有点像前述的静态划分?本人不是这样设计的,在此只留一个思路。

结语

每种策略都有胜过其他策略的时候,也都有自己犯傻的时候。所以实际上本单元作业不用太过在意使用哪种策略,保持程序的简洁与正确更加重要(此时某人内心在滴血)。就像现实生活中的电梯,你不能为了响应请求最快而不考虑安全性。
当然,最后我还是想吐槽——即便知道这是为了训练而迫不得已的设置——

“时至今日,我们仍没有搞明白,为啥从2层上到3层,不能爬”

你可能感兴趣的:(你的电梯,我的电梯,大家的电梯)