从上次作业到现在,课下又完成了一个电梯调度算法,Gitee链接如下:
https://gitee.com/yongwei-wang/elevator
1.算法思想
初始阶段各电梯在楼层中均匀分布,有请求事件发生时,采用LOOK算法运送乘客,即优先对同方向乘客需求进行响应,如果同方向乘客按下电梯按钮,则将该乘客加入到该电梯的队列中,优先顺路工作电梯(包括有载电梯),其次休息电梯; 无请求时:为节省电梯运行的耗电量,电梯执行完任务后,停在当前楼层进入休息状态,等待新的事件。
一期指标是乘客等待时间,二期指标以电梯磨损程度又加上了耗电量作为指标,但是发现源码和文档描述不符,源码的比例是:1:1.2,文档是1:2,尝试分配给电梯不同的响应权重,但发现运行过程中,这一权值的影响很小,LOOK算法本身已经保证了最小耗电量,于是保留LOOK算法。
2.PSP记录表
| PSP 各个阶段 | 预估时间(分钟) | 实际记录(分钟) |
|---|---|---|
| 计划: 明确需求和其他因素,估计以下的各个任务需要多少时间 | 60 | 60 |
| 开发(包括下面 8 项子任务) | 720 | 660 |
| · 需求分析(包括学习新技术、新工具的时间) | 30 | 30 |
| · 生成设计文档(整体框架的设计、各模块的接口、用时序图、快速原型等方法) | 60 | 60 |
| · 设计复审(和同事审核设计文档,或者自己复审) | 30 | 30 |
| · 代码规范(为目前的开发制定或选择合适的规范) | 60 | 0 |
| · 具体设计(用伪代码、流程图等方法来设计具体模块) | 60 | 60 |
| · 具体编码 | 300 | 300 |
| · 代码复审 | 60 | 0 |
| · 测试(自测测试、修改代码、提交修改) | 120 | 180 |
| 报告 | 120 | 120 |
| · 测试报告(发现了多少 bug,修复了多少) | 60 | 60 |
| · 计算工作量(多少行代码、多少次提交、多少测试用例、其他工作量) | 15 | 15 |
| · 事后总结,并提出改进计划(包括写文档、博客的时间) | 45 | 45 |
| 总共花费的时间(分钟) | 840 | 780 |
3.接口设计
3.1内部状态封装
构造了OptimizedLookController类,隐藏了电梯方向、目标楼层、乘客目的地、楼层请求等信息,使用时只需调用_smart_assign_elevator方法。
3.2清晰的回调接口
当这些事件发生时系统会调用对应方法
def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str) -> None
def on_elevator_stopped(self, elevator: ProxyElevator, floor: ProxyFloor) -> None
def on_elevator_idle(self, elevator: ProxyElevator) -> None
def on_passenger_board(self, elevator: ProxyElevator, passenger: ProxyPassenger) -> None
3.3一致的参数设计
所有电梯相关方法都接收 ProxyElevator 对象
所有楼层相关方法都接收 ProxyFloor 对象
所有乘客相关方法都接收 ProxyPassenger 对象
3.4松耦合
class OptimizedScanController(ElevatorController):
# 依赖于抽象的 ElevatorController 基类,而非具体实现
def on_init(self, elevators: List[ProxyElevator], floors: List[ProxyFloor]) -> None:
# 使用代理模型,不直接依赖具体的数据结构
pass
3.5模块间最小依赖
调度算法模块只依赖标准库和抽象接口
from typing import Dict, List, Set
from elevator_saga.client.base_controller import ElevatorController # 抽象基类
from elevator_saga.client.proxy_models import ProxyElevator, ProxyFloor, ProxyPassenger # 数据模型
3.6事件驱动的解耦
def on_passenger_call(self, passenger: ProxyPassenger, floor: ProxyFloor, direction: str) -> None:
# 乘客呼叫事件与具体调度逻辑解耦
# 系统触发事件,控制器响应事件,两者独立变化
self._smart_assign_elevator(floor.floor, direction)
4.算法评价
因为elevator-0.04包默认认为最后乘客都到达,输出的参数矩阵误导性极强,而且评价指标不包括用户达到率,导致在前期开发忽略了这个参数,仅将时间参数测试到了最优,所以算法的完成时间在班上排名是比较高的。因为算法是我独立写的,突然到截至时间时没时间改代码,所以因为算法缺陷导致很多乘客没接到,我重新反思了算法的细节,发现主要问题在于调度策略上,之前的策略是:优先有载顺路电梯,然后顺路电梯,然后休息电梯;但是没考虑电梯都在运行状态,此时算法会等待LOOK执行,所以导致有些乘客超时等待,所以算法加了一个强制分配策略,在都不满足的情况,确保乘客都能上电梯。
优势:
-
更高的请求响应速度(三级分配 vs 单一扫描)
-
更好的多电梯协作(智能分配 vs 独立运行)
-
更均匀的负载分布(评分系统考虑负载)
5.修改过程
整个算法模块化高,每次只需要改控制器部分,每次测试通过以后都会新创建一个文件,在另一个文件修改,因为整个代码是我独立开发的,所以gitee上我只需创建一个分支。不过提交的时候,遇到elevator库更新的问题,导致本地的server与测试环境不一样,最后在库里删除elevator_saga就行了。
6.代码规范
变量名根据用途来写,每个函数和类名都有详细注释,因为修改的elevator库本地只能用一次,然后要重启,不知道发生了什么,所以程序加了一个通讯测试,结对编程,最终和自己达成了共识,期末作业引以为戒。
7.界面模块
为了保证跨平台兼容性,我采用pyqt6作为前端框架,整体采用MVC模式,调度算法作为模型,QT用于可视化,然后将信息与可视化进行连接。

8.结对照片

9.合作模式
驾驶员-乘客模式
同伴的优点:
信任自己的同伴;上课不迟到;擅于做笔记。
缺点:
算法、代码能力、责任心有待提升。
10.PSP差异
开始另一个同伴找我结对编程,当时没注意另一位同学的基础,所以后期没产生有效沟通,差别时间主要是少了讨论部分。
11.其他收获
说来惭愧,写了这么久代码了,第一次使用gitee发布项目,发现了这一工具的便捷性,但提交过程还是涉及不同电脑间差别的问题,比如助教在本地修改了server库,我还把server库打包进gitee,就导致我的程序在测评环境运行不起来,也是积累了经验教训。
此次也发现AI工具用于前端开发的优势,它能迅速开发出一个框架,有开发经验,只需微调即可,大大降低了开发时间。
如果是比赛,算法的时间是优势,但之前被误导了,没考虑乘客响应超时问题。

被折叠的 条评论
为什么被折叠?



