BUAA OO U2 总结

刘鸣翔-22371462 2024-04-20 15:53:11

作业总述

这一单元作业的架构思路最初来源于性能分的计算公式:

img

首先,从图中的公式可以看出,一个中庸的实现(假设自己的 x 正好是 base 的 max 与 min 的平均数)就可以得到90%的性能分。此外,性能分有三个评价指标,而且评价指标间大体上相互矛盾,在当时的我看来几乎不可能有一种靠谱的算法可以保证性能的最优(尤其是在强测数据分布未知的情况下)。因此,我在 hw5 初步设计架构时,着重考虑了以下两点:

  • 尽可能使自己的调度策略兼顾系统运行时间、等待时间与期望时间之差的最大值和系统耗电量,不追求某一指标的极致优化,而是尽力避免任一指标过劣的情况。
  • 尽可能保证程序的正确性。

基于上述思想,我选择了比较基本的 ALS 策略(毕竟出现在作业指导书中的算法很可能成为主流)、放弃了调度器(比较好的随机竞争的调度策略可能更接近平均)、在一些细节上采用了更保守的处理(以性能换可靠性)。

这两条原则也用到了 hw6 作业中(于是我的hw6设计中没有中央调度器)。但在 hw6 后,我发现情况与预想的不太一样。许多同学用了影子电梯、量子电梯与look策略,于是朴素的ALS策略相比之下性能会比较差。而且强测的数据点数量很有限,并且应该是特殊选取的。最终在 hw6 的强测中有若干数据点性能分接近满分,有数量几乎相同的数据点性能分接近没有,另有若干数据点介于两者之间,最后性能分只有一半,以另一种方式实现了中庸
回看,其实朴素的ALS策略随机性比较差,在某些数据下表现会很糟糕,但过分地引入随机又可能导致性能的普遍降低,因此还是需要一个调度器来在普遍性能与随机性之间做平衡。但毕竟在hw6中没有实现调度器,在 hw7 中加入调度器工作量会很大,并且带来的性能提升不会太多(一个简单的调度器没有任何理由打败影子电梯,而即使是影子电梯也不都能做到“中庸的实现”),于是在 hw7 中我沿用了自由竞争的策略,最后性能分也只有一半 (果然)

虽然性能分无了,但这样的设计策略还是给代码编写与bug排查带来了很大的便利。最大的优势就是在线程的安全性上。由于不存在调度器,程序全程只有电梯线程与 Input 线程轮换着读写数据。只需要设置一个全局的锁,得到该锁的线程可以访问任意公共区的数据,仅仅这样就可以实现线程安全。由于不追求局部的极致性能,因此电梯 wait 可以全部设计为定时唤醒(如果电梯空闲就以一定的频率轮询),这样整个程序中就可以不用 notify ,也就不必记录时间戳,大大简化了程序的逻辑。

整体架构

ULM类图

img

UML协作图

img

分析

从图表中可以看出,我在 hw6 与 hw7 的迭代中在原有设计上增加了内容,没有进行大规模的重构,并且线程设计相对简单。
在三次作业中,稳定的内容主要是 Passenger 类、 MainWaitingQueue 类,而变化较大的类主要是 Elevator 类(由于对 reset 进行了特殊处理,在 hw6 迭代中加入的 reset 会改变电梯的运作模式)、Input 类(需要对新的请求类型进行解析)。

调度策略分析

三次作业中我采取的都是一种类似于自由竞争的策略。因此,我在设计时没有加入中央调度器,只采用了电梯的局部调度器,由电梯自主选取乘客。

调度策略:

电梯如果要运行,首先需要选定主乘客。如果电梯内没有乘客,则选取中央等待队列中的第一个乘客作为主乘客。
电梯选定主乘客后,输出 Receive,前往主乘客处,中途允许搭载。
电梯接受主乘客后,前往主乘客的目的地,中途允许搭载。
如果电梯开始 reset ,则立刻(或者尽快)将所有乘客抛出,并开始 reset

指标平衡:

  • 按照乘客到来时间决定乘客优先级,而非电梯与乘客的距离。这样可以让早到的乘客尽可能先得到服务,并且如果每次都选取最近/最远的乘客,可能导致总运行时间/电梯电量性能过差。相比之下,按时间决定优先级是一个折中的、比较随机的策略。

  • 在向中央等待队列中加入乘客时我引入了一些随机性,即在新用户加入主请求队列时,将其插入队首。虽然可能会让原来的乘客等待更长时间,但新加入的乘客可能是换乘乘客,这样做可以一定程度上避免他们等待过长时间,也可以避免构造数据导致调度效率低下。

实现双轿厢的两个轿厢不碰撞

由于设计的特殊性,得到全局锁的电梯可以访问全部公共区信息。双轿厢电梯只需要创建一个两个子电梯的信息共享区,并存储换乘楼层的占用情况。当一个子电梯需要进入/离开换乘楼层时,修改公共区内容即可。如果一个电梯需要进入换乘楼层,并且另一个子电梯正在换乘楼层,那么该电梯先等待,并向公共区域写入请求,等换乘楼层空闲时再进入。

bug、hack与debug

  • bug:虽然很多细节处理得比较保守,但在 hw6 中还是出现了电梯运行时乘客未达目的地的bug。hw6的作业要求输出 recieve ,而我对某些被 receive 的乘客进行特殊处理时出现了错误。其实这个 bug 比较容易发现,但我三次作业都没有经过评测机自测,代码走查又不够仔细,在加大走查力度后实现了 hw7 的无伤。
  • hack:由于没有评测机,对同房的代码只能进行样例级别的hack,但是单靠一条reset就能在 hw6 与 hw7 互测中 hack 到4个同学(?)
  • debug:由于线程的安全已经得到了保证,因此几乎所有的 bug 都是出现在电梯的运行逻辑中,只要采用常规的单线程 debug 方式就可以找出 bug 。此外,对逻辑比较复杂的部分进行走查来找bug确实是很有必要的。

体会与反思

架构设计要三思而后行。这次没有中央调度器的离奇设计虽然还算顺利地通过了 hw7,但从性能与可扩展性的角度上将都不如有中央调度器的设计。在对新的需求进行设计架构时要对之前的设计进行审视,让程序能适应新的潜在需求。还要注意程序中的某些细节。这次的作业中我写许多性能细节都没有处理(比如电梯等待的轮询),这也为性能分爆炸埋下伏笔。
这一单元的课程中,我尝试了新的测试方式。由于上一单元被依赖评测机的习惯坑过,在这一单元的作业中,我没有使用评测机,而是尝试用走查的方式解决程序中的 bug。hw6 的代码走查不仔细,结果出现了 bug 。在 hw7 的中测 debug 中,我采用只看评测结果,不看解释信息的方式,去盲找程序中可能出现的问题。这样的走查可能发现一些比较明显的、测试无法覆盖的问题,不失为对中测的一个补充。
在这次作业中,我对于线程安全的实现比较简单粗暴,没有遇见死锁等多线程的 bug。在以后的作业中我应该尽早研究与死锁相关的问题,避免以后线程变复杂时出现死锁。

...全文
58 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

301

社区成员

发帖
与我相关
我的任务
社区描述
2023年北航面向对象设计与构造
学习 高校
社区管理员
  • YannaZhang
  • CajZella
  • C_ecelia
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧