离散事件
模拟将系统随时间的变化抽象成一系列的离散时间点上的事件,通过按照事件时间顺序处理事件来演进,是一种事件驱动的仿真世界观。离散事件仿真将系统的变化看做一个事件,因此系统任何的变化都只能是通过处理相应的事件来实现,在两个相邻的事件之间,系统状态维持前一个事件发生后的状态不变。
0 概述
SimPy 是一个用于在 Python 中进行离散事件模拟的库。它提供了一个简单而强大的框架,用于模拟各种系统,例如:
- 生产线: 模拟生产线上的机器、工人和产品流动。
- 网络: 模拟网络中的路由器、交换机和数据包传输。
- 交通系统: 模拟交通灯、车辆和道路网络。
- 计算机系统: 模拟 CPU、内存、磁盘和程序执行。
1 目标
我们将要实现以下功能的模拟:
有一个仓库,里面会有若干个巷道
- 每个巷道,分左右两部分 (假设所有巷道的货架规格相同)
- 每个巷道一个机器人 (机器人在出口位置,等待执行指令,执行完毕后将货物放置在出口)
现在会给这个仓库发送一些取货指令 (不考虑货格货物状态,假设货物无限)
- 仓库接收到指令后,会根据巷道编号 分配给具体的巷道
- 巷道会将指令转发给机器人
- 机器人启动执行任务,取出货物后,再送至出口等待下一条任务
- 耗时按货物所处的层、列,乘以各自的系数得到
2 抽象
2.1 对象
主要考虑对象的 name
名称,env
仿真环境
class Object(object):
name: str = None
env: Environment = None
2.2 系统
一个系统:
- 会有
start
和stop
两个开关操作。 - 同时,还能接收外部的
push_task
推送任务操作。 - 然后将任务存储至自身的
task_list
任务池中. - 启动后,会不断地从任务池中,
choose_task
选取任务来run
执行。 - 执行完后,再根据一定的(业务)规则,
push_task②
推送至其他系统中。
class System(Object, abc.ABC):
"""
系统
"""
def __init__(self, name: str, env: Environment):
super().__init__(name, env)
self.task_list = []
self.running = False
def push_task(self, task: Task):
logger.debug(f'{self.name} 接收到任务 {task.name}')
self.task_list.append(task)
def run(self):
while self.running:
if not self.task_list:
yield self.env.timeout(1)
continue
task = self.choose_task()
# 处理该任务
yield self.env.process(self.run_task(task))
def choose_task(self) -> Union[Task, None]:
"""
当任务列表有任务时,根据一定的策略从任务列表选取一个出来
:return:
"""
if self.task_list:
return self.task_list.pop(0)
return None
@abc.abstractmethod
def run_task(self, task: Task):
"""
具体的任务执行
:param task:
:return:
"""
pass
def start(self):
logger.debug(f'{self.name} 开始启动')
self.running = True
self.env.process(self.run())
def stop(self):
self.running = False
logger.debug(f'{self.name} 停止运动')
3 建模
3.1 位置
主要有巷道、方向、以及几层几列。
class Position(object):
lane: int = None
direction: Direction = None
layer: int = None
column: int = None
3.2 任务
主要有任务名称、位置,以及一个辅助字段: 任务状态。
class Task(object):
def __init__(self, tid: str, name: str, position: Position):
self.tid = tid
self.name = name
self.position = position
self.status = TaskStatus.READY
3.3 仓库
根据配置信息,生成巷道数据
class Warehouse(System):
def __init__(self, name: str, env: Environment):
super().__init__(name, env)
self.shelf_list: list[Shelf] = []
self.__init()
3.4 巷道
主要关联机器人。(理论上两个Shelf组成一个巷道。实际并不会对仿真产生影响,故简化)
class Shelf(System):
def __init__(self, name: str, robot: Robot, env: Environment):
super().__init__(name, env)
self.env = env
self.robot = robot
3.5 机器人
主要用来执行任务。在执行任务过程中,核心点为: 资源的占用
,耗时的计算
。
class Robot(System):
def __init__(self, name: str, env: Environment):
super().__init__(name, env)
self.resource = Resource(env)
4 运行测试
2024-06-27 14:55:09.618 | DEBUG | __main__:start:129 - 机器人_01 开始启动
2024-06-27 14:55:09.618 | DEBUG | __main__:start:129 - 货架_1 开始启动
2024-06-27 14:55:09.618 | DEBUG | __main__:start:129 - 机器人_02 开始启动
2024-06-27 14:55:09.618 | DEBUG | __main__:start:129 - 货架_2 开始启动
2024-06-27 14:55:09.618 | DEBUG | __main__:start:129 - 机器人_03 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:start:129 - 货架_3 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:start:129 - 机器人_04 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:start:129 - 货架_4 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:start:129 - 机器人_05 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:start:129 - 货架_5 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:start:129 - 仓库 开始启动
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_01
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_02
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_03
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_04
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_05
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_06
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_07
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_08
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_09
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 仓库 接收到任务 任务_10
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_3 接收到任务 任务_01
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_3 接收到任务 任务_02
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_3 接收到任务 任务_03
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_5 接收到任务 任务_04
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_4 接收到任务 任务_05
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_1 接收到任务 任务_06
2024-06-27 14:55:09.619 | DEBUG | __main__:push_task:98 - 货架_4 接收到任务 任务_07
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 货架_3 接收到任务 任务_08
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 货架_5 接收到任务 任务_09
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 货架_2 接收到任务 任务_10
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_01 接收到任务 任务_06
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_02 接收到任务 任务_10
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_03 接收到任务 任务_01
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_04 接收到任务 任务_05
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_05 接收到任务 任务_04
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_03 接收到任务 任务_02
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_04 接收到任务 任务_07
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_05 接收到任务 任务_09
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_03 接收到任务 任务_03
2024-06-27 14:55:09.621 | DEBUG | __main__:push_task:98 - 机器人_03 接收到任务 任务_08
2024-06-27 14:55:09.621 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_01 开始任务执行 task: 任务_06(lane: 01(1), layer: 06, column: 10), time: 2024-06-27 14:55:11
2024-06-27 14:55:09.621 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_02 开始任务执行 task: 任务_10(lane: 02(1), layer: 17, column: 01), time: 2024-06-27 14:55:11
2024-06-27 14:55:09.621 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_03 开始任务执行 task: 任务_01(lane: 03(1), layer: 30, column: 10), time: 2024-06-27 14:55:11
2024-06-27 14:55:09.621 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_04 开始任务执行 task: 任务_05(lane: 04(2), layer: 23, column: 19), time: 2024-06-27 14:55:11
2024-06-27 14:55:09.621 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_05 开始任务执行 task: 任务_04(lane: 05(1), layer: 26, column: 12), time: 2024-06-27 14:55:11
2024-06-27 14:55:09.622 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_01 完成任务执行 task: 任务_06(lane: 01(1), layer: 06, column: 10), time: 2024-06-27 14:55:55, cost: 44
2024-06-27 14:55:09.622 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_02 完成任务执行 task: 任务_10(lane: 02(1), layer: 17, column: 01), time: 2024-06-27 14:56:21, cost: 70
2024-06-27 14:55:09.622 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_05 完成任务执行 task: 任务_04(lane: 05(1), layer: 26, column: 12), time: 2024-06-27 14:57:19, cost: 128
2024-06-27 14:55:09.622 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_05 开始任务执行 task: 任务_09(lane: 05(1), layer: 19, column: 19), time: 2024-06-27 14:57:19
2024-06-27 14:55:09.622 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_04 完成任务执行 task: 任务_05(lane: 04(2), layer: 23, column: 19), time: 2024-06-27 14:57:21, cost: 130
2024-06-27 14:55:09.622 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_04 开始任务执行 task: 任务_07(lane: 04(2), layer: 16, column: 18), time: 2024-06-27 14:57:21
2024-06-27 14:55:09.623 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_03 完成任务执行 task: 任务_01(lane: 03(1), layer: 30, column: 10), time: 2024-06-27 14:57:31, cost: 140
2024-06-27 14:55:09.623 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_03 开始任务执行 task: 任务_02(lane: 03(1), layer: 25, column: 14), time: 2024-06-27 14:57:31
2024-06-27 14:55:09.624 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_04 完成任务执行 task: 任务_07(lane: 04(2), layer: 16, column: 18), time: 2024-06-27 14:59:01, cost: 100
2024-06-27 14:55:09.624 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_05 完成任务执行 task: 任务_09(lane: 05(1), layer: 19, column: 19), time: 2024-06-27 14:59:13, cost: 114
2024-06-27 14:55:09.624 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_03 完成任务执行 task: 任务_02(lane: 03(1), layer: 25, column: 14), time: 2024-06-27 14:59:39, cost: 128
2024-06-27 14:55:09.624 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_03 开始任务执行 task: 任务_03(lane: 03(2), layer: 17, column: 04), time: 2024-06-27 14:59:39
2024-06-27 14:55:09.625 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_03 完成任务执行 task: 任务_03(lane: 03(2), layer: 17, column: 04), time: 2024-06-27 15:00:55, cost: 76
2024-06-27 14:55:09.625 | DEBUG | __main__:run_task:172 - [ROBOT] 机器人_03 开始任务执行 task: 任务_08(lane: 03(2), layer: 09, column: 20), time: 2024-06-27 15:00:55
2024-06-27 14:55:09.626 | DEBUG | __main__:run_task:177 - [ROBOT] 机器人_03 完成任务执行 task: 任务_08(lane: 03(2), layer: 09, column: 20), time: 2024-06-27 15:02:11, cost: 76
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 仓库 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 货架_1 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 机器人_01 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 货架_2 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 机器人_02 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 货架_3 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 机器人_03 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 货架_4 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 机器人_04 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 货架_5 停止运动
2024-06-27 14:55:09.626 | DEBUG | __main__:stop:135 - 机器人_05 停止运动
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。