SimPy是基于标准Python语言的基于过程的离散事件仿真框架。SimPy中的进程由Python的generator函数定义,例如,可以用于对客户、车辆或智能体等活动组件进行建模。SimPy还提供各种类型的共享资源来模拟有限容量的拥塞点(如服务、收银台和通道)。
SimPY使用Environment,Process,Event,Resource四大概念来进行离散事件的仿真。
①Environment就是整体仿真所在的时间,主要用于提取时间。
②Process就是仿真过程中的实体,如:顾客, 设备, 车辆等。 Process本质上也是一个event。源代码里面可以看到是继承Event的一个类。
SimPy进程(由Process或env.Process()创建)也具有作为事件的良好属性。这意味着,一个过程可以产生另一个过程。当另一个进程结束时,它将被恢复。事件的值将是该进程的返回值:
③Event是仿真中触发的事件,可以理解为一个定时器。当定时器到时时,触发事件。
④Resource是仿真中的资源,如ATM机,服务器等。
活动组件(顾客)的行为由进程(Processes)进行建模。所有进程都存在于同个环境中。它们通过事件与环境相互作用。
进程由简单的Python生成器描述。您可以通过function或method调用它,这取决于它是一个普通函数还是一个类的方法。进程在生命周期中可以创造并挂起(yield)事件(Events),等待事件的触发。
当进程生成事件时,该进程将被挂起。当事件发生时(事件已触发),SimPy恢复进程。多个进程可以等待同一事件。SimPy按照生成事件的统一顺序进行恢复。
一个重要的事件类型是超时(Timeout)。此类事件在经过一定仿真时间后被触发。它们允许进程在给定的时间内睡眠(或保持其状态)。可以通过调用进程所在环境的适当方法(例如Environment.Timeout())来创建超时事件和所有其他事件。
Environment 决定仿真的起点/终点, 管理仿真元素之间的关联, 主要 API 有
simpy.Environment.process - 添加仿真进程
simpy.Environment.event - 创建事件
simpy.Environment.timeout - 提供延时(timeout)事件
simpy.Environment.until - 仿真结束的条件(时间或事件)
simpy.Environment.run - 仿真启动
def Client(env, name, sm):
"""
客户到达超市,挑选商品,结账流程,结束后离开
"""
time_start=env.now #顾客到达超市的时间点
print('%s 到达超市 at %.2f.' % (name, env.now))
yield env.timeout(expon.rvs(scale=4)) # 假设挑选时间 指数分布
print('%s 挑选商品完成 at %.2f.' % (name, env.now))
timeChoose=env.now-time_start
with sm.checkstand.request() as request:
yield request
timeWait=env.now-time_start-timeChoose
print('%s 开始结账 at %.2f.' % (name, env.now))
yield env.process(sm.serve(name))
print('%s 结账离开超市 at %.2f.' % (name, env.now))
time_end = env.now #顾客离开超市的时间点
time_arr.append(time_end-time_start) #加入总时间数组
chooseTime.append(timeChoose) #挑选时间
waitTime.append(timeWait) #等待时间
顾客的进程需要引用环境(env)来创建新的事件
资源(resource)的request()方法生成一个事件(event), 该事件会等待直至资源可用。您将“拥有”资源,直至资源被释放。
在代码中使用with构造资源的请求使用,资源在使用后将自动释放。如果没通过with使用request(),您需要自行使用release()释放资源。
当您释放资源后,下一个等待的进程将激活,“占用”资源。资源的排队规则遵循先进先出(first in—first out,FIFO)策略。
创建资源: self.checkstand = simpy.Resource(env, NUM_CHECKSTANDS)
超市进程:
class SuperMarket(object):
"""
一个超市,拥有指定数目的收银台。
"""
def __init__(self, env, NUM_CHECKSTANDS):
self.env = env
self.checkstand = simpy.Resource(env, NUM_CHECKSTANDS) # 创建资源
def serve(self, client):
"""结账时间固定为30秒(0.5分钟),使用一个顾客进程"""
print("收银台开始为%s提供服务" % client)
yield self.env.timeout(SERVICE_TIME) # 假设服务时间0.5分钟
顾客等待资源:
with sm.checkstand.request() as request:
yield request
def setup(env, NUM_CHECKSTANDS,CLIENT_NUMBER):
"""创建一个超市,有三个结账窗口"""
# 创建超市
supermarket = SuperMarket(env, NUM_CHECKSTANDS)
i=0 #客户数目
# 在仿真过程中持续创建客户(直至500)
while True:
yield env.timeout(poisson.rvs(mu=1)) # 顾客到达超市的时间间隔服从泊松分布, lambd设为1
i += 1
env.process(Client(env, '顾客【%d】' % i, supermarket)) # 创建顾客进程,还有其交互的超市进程
if i==CLIENT_NUMBER :
break