优化电梯调度2:从优先级调度到流量预测的全方位解决方案
概述:
写作原由:
在现代建筑中,电梯系统不仅仅是垂直交通工具,它们是建筑物运行效率的关键组成部分。随着建筑高度的增加和人流量的增长,传统的电梯调度系统已无法满足高效运行的需求。因此,开发一个能够智能调度并优化乘客流量的电梯控制系统变得至关重要。本文介绍了一个先进的电梯控制器 ElevatorController
的设计和实现,以及如何通过模拟系统 ElevatorSystemSimulation
来验证其效果。
ElevatorController 实现
首先,重新审视了电梯调度的核心问题。在高峰时段,电梯的需求激增,如果仅仅依靠传统的先到先服务原则,将无法有效处理紧急或优先级更高的呼叫。为了解决这一问题,引入了一个基于优先级的队列系统,使得电梯能够根据不同请求的紧急程度进行响应。这样,例如,在上班高峰时段,电梯可以优先响应到达地面层的请求,而在下班高峰时段,则优先响应从办公室层返回地面层的请求。
import java.util.List;
import java.util.ArrayList;
/**
* @Author derek_smart
* @Date 2024/6/5 9:41
* @Description
* ElevatorController 类是电梯调度系统的核心,负责协调和管理一组电梯的操作。
* 它使用优先级队列来处理来自不同楼层的电梯呼叫请求,并根据请求的紧急程度、预测的乘客流量
* 和电梯的当前状态来动态调度电梯。此外,ElevatorController 还负责启动和停止所有电梯的运行。
* 主要功能包括:
* - 接收电梯呼叫请求。
* - 根据优先级、电梯位置和预测的流量数据调度电梯。
* - 启动和停止所有电梯的运行。
* - 通过 TrafficPredictor 组件利用历史流量数据来预测和调整优先级。
*
* 使用方法:
* 创建 ElevatorController 实例时,需要指定管理的电梯数量和建筑物的楼层数。
* 使用 dispatchRequest 方法来添加新的电梯呼叫请求。
* 使用 startAllElevators 和 stopAllElevators 方法来控制电梯的运行。
*/
public class ElevatorController {
private List<AdvancedElevator> elevators;
private List<Thread> elevatorThreads; // 用于管理电梯线程的列表
private TrafficPredictor trafficPredictor;
public ElevatorController(int numberOfElevators, int topFloor) {
elevators = new ArrayList<>(numberOfElevators);
elevatorThreads = new ArrayList<>(numberOfElevators);
for (int i = 0; i < numberOfElevators; i++) {
AdvancedElevator elevator = new AdvancedElevator(0, topFloor);
elevators.add(elevator);
elevatorThreads.add(new Thread(elevator)); // 创建电梯的线程并添加到列表中
}
trafficPredictor = new TrafficPredictor(); // 假设这是一个使用历史数据预测流量的类
}
public void dispatchRequest(int floor, int priority) {
// Adjust the priority based on traffic prediction
int adjustedPriority = trafficPredictor.adjustPriority(floor, priority);
// Find the best elevator to handle the request
AdvancedElevator bestElevator = findBestElevator(floor);
bestElevator.callElevator(floor, adjustedPriority);
}
private AdvancedElevator findBestElevator(int floor) {
// Implement logic to find the best elevator based on current location, direction, and load
// This is a placeholder for the actual logic
return elevators.get(0); // Simplified for the example
}
// 启动所有电梯的方法
public void startAllElevators() {
for (Thread thread : elevatorThreads) {
thread.start(); // 启动每个电梯的线程
}
}
// 停止所有电梯的方法
public void stopAllElevators() {
for (AdvancedElevator elevator : elevators) {
elevator.stopElevator(); // 通知每个电梯停止运行
}
for (Thread thread : elevatorThreads) {
try {
thread.join(); // 等待每个电梯的线程终止
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
时序图:
时序图中,可以看到以下步骤:
-
用户(User)创建了
ElevatorController
实例。 -
ElevatorController
实例化了一组Elevator
对象。 -
ElevatorController
调用startAllElevators()
方法来启动所有电梯。 -
每个
Elevator
开始运行。 -
在每次请求的循环中:
a. 用户向
ElevatorController
发送dispatchRequest
,包含楼层和优先级。b.
ElevatorController
请求TrafficPredictor
预测当前的交通流量。c.
TrafficPredictor
返回交通流量水平(trafficLevel)。d.
ElevatorController
根据调整后的优先级分配最合适的电梯。e. 分配的
Elevator
移动到指定的楼层。 -
用户要求停止所有电梯。
-
ElevatorController
调用每个Elevator
的stopElevator()
方法。 -
每个
Elevator
停止并通知ElevatorController
已经停止。
此外,为了管理多部电梯并实现它们之间的协同工作,设计了 ElevatorController
。它负责接收所有电梯的请求,并根据电梯的当前状态、预测的乘客流量以及请求的优先级来分配任务。通过这种集中式的管理方式,能够确保电梯群体以最优的方式运行,避免了不必要的等待和空驶。
TrafficPredictor 实现:
接下来,考虑了如何利用历史流量数据来进一步优化电梯调度。通过引入 TrafficPredictor
组件,的系统能够预测不同时间段的乘客流量,并据此调整请求的优先级。这种基于预测的调度策略不仅提高了电梯的运行效率,也提升了乘客的满意度。
TrafficPredictor类的目的是使用历史数据和可能的预测模型来预测电梯的乘客流量,并据此调整电梯呼叫请求的优先级。在实际应用中,这可能包括机器学习或统计分析方法。 以下是一个简化的
TrafficPredictor` 类的代码示例,它基于简单的规则来模拟流量预测和优先级调整:
import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;
/**
* @Author derek_smart
* @Date 2024/6/5 9:41
* @Description TrafficPredictor 类用于预测电梯的乘客流量,并根据预测结果调整呼叫请求的优先级。
* 它根据时间段和历史乘客流量数据来预测流量,然后使用这些信息来优化电梯调度。
* <p>
* 注意:这是一个简化的示例,实际应用中可能需要复杂的数据分析和机器学习方法。
*/
public class TrafficPredictor {
// 存储不同时间段的流量模式
private Map<TimeRange, Integer> trafficPatterns;
public TrafficPredictor() {
trafficPatterns = new HashMap<>();
// 假设数据:初始化不同时间段的预期流量等级
// 例如,早上8点到9点是最高流量等级5
trafficPatterns.put(new TimeRange(LocalTime.of(8, 0), LocalTime.of(9, 0)), 5);
trafficPatterns.put(new TimeRange(LocalTime.of(9, 0), LocalTime.of(10, 0)), 3);
// ... 添加其他时间段的流量模式 ...
}
/**
* 根据当前时间和楼层来调整请求的优先级。
*
* @param floor 请求的目标楼层
* @param originalPriority 原始请求优先级
* @return 调整后的优先级
*/
public int adjustPriority(int floor, int originalPriority) {
int trafficLevel = predictTrafficLevel();
// 根据当前流量等级调整优先级,这里只是简单地将流量等级加到原始优先级上
return originalPriority + trafficLevel;
}
/**
* 预测当前时间段的流量等级。
*
* @return 流量等级
*/
private int predictTrafficLevel() {
LocalTime now = LocalTime.now();
// 遍历时间段,找出当前时间所属的流量等级
for (Map.Entry<TimeRange, Integer> entry : trafficPatterns.entrySet()) {
if (entry.getKey().isWithinRange(now)) {
return entry.getValue();
}
}
// 如果不在已定义的时间段内,默认返回最低流量等级
return 1;
}
/**
* TimeRange 类表示一段时间范围。
*/
private static class TimeRange {
private final LocalTime start;
private final LocalTime end;
public TimeRange(LocalTime start, LocalTime end) {
this.start = start;
this.end = end;
}
/**
* 检查给定的时间是否在此时间范围内。
*
* @param time 要检查的时间
* @return 如果时间在范围内,则返回 true
*/
public boolean isWithinRange(LocalTime time) {
return !time.isBefore(start) && time.isBefore(end);
}
}
}
代码解析:
TrafficPredictor
类包含了一个 trafficPatterns
映射,它存储了不同时间段的预期流量等级。这些数据可以基于历史流量数据来设置。adjustPriority
方法接受一个楼层和一个原始优先级,然后调用 predictTrafficLevel
方法来获取当前时间段的流量等级,并据此调整优先级。
TimeRange
是一个内部类,用于表示一段时间范围,并提供一个方法来检查给定时间是否在这个范围内。
时序图:
时序图,可以看到以下步骤:
ElevatorController
请求TrafficPredictor
预测当前时间段的交通流量等级。TrafficPredictor
从HistoricalData
存储中检索与当前时间相关的数据。HistoricalData
返回相关的流量数据给TrafficPredictor
。TrafficPredictor
使用PredictionModel
来处理历史流量数据并预测流量等级。PredictionModel
返回预测的流量等级给TrafficPredictor
。TrafficPredictor
将预测的流量等级转换为调整后的优先级,并返回给ElevatorController
。
这个示例是简化的,并没有使用复杂的预测算法。在实际应用中,可能需要收集大量的历史数据,并使用统计分析或机器学习方法来建立更准确的预测模型。
AdvancedElevator实现:
这个类的实现在之前的文章中已经介绍了,故此不再详细介绍,只贴出对应的代码
import java.util.PriorityQueue;
import java.util.Comparator;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @Author derek_smart
* @Date 2024/6/5 9:41
* @Description
* <p> 带优先级轮询
*/
public class AdvancedElevator implements Runnable {
private int currentFloor;
private final int topFloor;
private final AtomicBoolean running = new AtomicBoolean(true);
private final PriorityQueue<ElevatorRequest> requestQueue;
public AdvancedElevator(int currentFloor, int topFloor) {
this.currentFloor = currentFloor;
this.topFloor = topFloor;
// Define the comparator for the priority queue based on priority and distance
Comparator<ElevatorRequest> requestComparator = Comparator
.comparingInt(ElevatorRequest::getPriority)
.thenComparingInt(req -> Math.abs(req.getFloor() - currentFloor));
this.requestQueue = new PriorityQueue<>(requestComparator);
}
public void callElevator(int floor, int priority) {
if (floor >= 0 && floor <= topFloor) {
requestQueue.add(new ElevatorRequest(floor, priority));
}
}
public void stopElevator() {
running.set(false);
}
@Override
public void run() {
while (running.get()) {
ElevatorRequest nextRequest = requestQueue.poll();
if (nextRequest != null) {
moveToFloor(nextRequest.getFloor());
}
// Sleep for a short time to simulate waiting for the next request
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
// Existing methods: moveToFloor, openDoors, closeDoors
private static class ElevatorRequest {
private final int floor;
private final int priority;
public ElevatorRequest(int floor, int priority) {
this.floor = floor;
this.priority = priority;
}
public int getFloor() {
return floor;
}
public int getPriority() {
return priority;
}
}
/**
* 控制电梯移动到目标楼层的方法。它会逐层移动电梯,直到到达目标楼层,并在每层停留一段时间模拟乘客进出。
* @param destinationFloor
*/
private void moveToFloor(int destinationFloor) {
while (currentFloor != destinationFloor && running.get()) {
if (currentFloor < destinationFloor) {
// Move up
currentFloor++;
} else {
// Move down
currentFloor--;
}
// Simulate the time it takes to move between floors
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("Elevator is at floor: " + currentFloor);
}
// Simulate stopping at the floor
if (running.get()) {
openDoors();
// Simulate time for passengers to enter/exit
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
closeDoors();
}
}
/**
* 模拟电梯在楼层开门
*/
private void openDoors() {
System.out.println("Opening doors at floor: " + currentFloor);
}
/**
* 模拟电梯在楼层关门。
*/
private void closeDoors() {
System.out.println("Closing doors at floor: " + currentFloor);
}
public static void main(String[] args) throws InterruptedException {
AdvancedElevator elevator = new AdvancedElevator(0, 10);
Thread elevatorThread = new Thread(elevator);
elevatorThread.start();
// Simulate some calls to the elevator
elevator.callElevator(3,3);
elevator.callElevator(7,1);
elevator.callElevator(5,10);
// Allow the elevator to process the calls
Thread.sleep(20000);
// Stop the elevator
elevator.stopElevator();
elevatorThread.join();
}
}
时序图:
时序图中,可以看到以下步骤:
-
ElevatorController
发送一个请求到AdvancedElevator
,包含目标楼层和优先级。 -
AdvancedElevator
请求ElevatorMotor
检查当前电梯的状态。 -
ElevatorMotor
返回电梯的状态(空闲或忙碌)给AdvancedElevator
。 -
如果电梯状态是空闲(Idle):
a.
AdvancedElevator
指示ElevatorDoor
关闭门。b.
ElevatorDoor
确认门已关闭。c.
AdvancedElevator
指示ElevatorMotor
移动到目标楼层。d.
ElevatorMotor
在接近目标楼层时通知Sensor
。e.
Sensor
通知AdvancedElevator
已到达目标楼层。f.
AdvancedElevator
指示ElevatorDoor
打开门。g.
ElevatorDoor
确认门已打开。h.
AdvancedElevator
通知ElevatorController
请求已完成。 -
如果电梯状态是忙碌(Busy): a.
AdvancedElevator
将请求加入队列,并通知ElevatorController
请求已排队。
ElevatorSystemSimulation 实现:
为了验证设计,创建了 ElevatorSystemSimulation
模拟程序。在这个模拟中,实例化了电梯控制器,并模拟了一系列的电梯请求。通过观察电梯如何响应这些请求,可以评估调度算法的性能,并进行必要的调整。
/**
* @Author derek_smart
* @Date 2024/6/5 9:42
* 模拟测试类
*/
public class ElevatorSystemSimulation {
public static void main(String[] args) {
// 建筑物有 3 部电梯,最高可达 10 层
ElevatorController controller = new ElevatorController(3, 10);
// 启动所有电梯线程
controller.startAllElevators();
// 模拟早晨上班高峰时段的电梯呼叫请求
controller.dispatchRequest(1, 5); // 地面层,优先级 5
controller.dispatchRequest(2, 3); // 2 楼,优先级 3
controller.dispatchRequest(6, 4); // 6 楼,优先级 4
// 等待一段时间让电梯处理请求
try {
Thread.sleep(10000); // 等待 10 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
// 模拟晚上下班高峰时段的电梯呼叫请求
controller.dispatchRequest(8, 5); // 8 楼,优先级 5
controller.dispatchRequest(9, 3); // 9 楼,优先级 3
controller.dispatchRequest(10, 4); // 10 楼,优先级 4
// 再次等待一段时间让电梯处理请求
try {
Thread.sleep(10000); // 等待 10 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
// 停止所有电梯线程
controller.stopAllElevators();
}
}
在这个模拟场景中,首先创建了一个名为 ElevatorSystemSimulation
的类,它的 main
方法是程序的入口点。实例化了 ElevatorController
,它管理着 3 部电梯,服务一个最高有 10 层的建筑物。
通过调用 startAllElevators
方法来启动所有电梯线程。然后,模拟了早晨上班高峰时段的几个电梯呼叫请求,这些请求通过 dispatchRequest
方法发送给 ElevatorController
。每个请求包含了一个目标楼层和一个优先级,其中优先级可以根据实际情况(如流量预测)进行动态调整。
为了让电梯有足够的时间处理这些请求,使用 Thread.sleep
方法等待了一段时间。在现实世界中,你可能会有一个更复杂的机制来决定何时发送请求和何时停止电梯。
在模拟了一段时间的运行后,通过调用 stopAllElevators
方法来停止所有电梯线程。这个方法确保所有电梯都优雅地完成了当前任务,并且所有电梯线程都被正确地关闭。
这个简单的示例展示了如何在一个多电梯系统中使用 ElevatorController
来处理电梯呼叫请求,并在完成操作后安全地停止所有电梯。在一个完整的电梯系统中,还需要考虑更多的功能和异常情况,例如电梯故障、紧急呼叫处理、用户界面交互、实时监控和日志记录等。
最后,如何安全地启动和停止电梯系统。在 ElevatorController
中,实现了 startAllElevators
和 stopAllElevators
方法,确保了在系统启动和关闭时,所有电梯都能够按照预期工作。
总结:
通过本文的介绍,展示了如何构建一个智能的电梯系统,从优先级调度到流量预测,再到多电梯协同工作,提供了一个全方位的解决方案,以满足现代建筑日益增长的交通需求。随着技术的进步,相信这样的系统将在未来的建筑设计中扮演越来越重要的角色。
转载自:https://juejin.cn/post/7376846965470937097