python语言例子_【Python】SimPy的使用示例-Go语言中文社区

使用SimPY进行离散事件仿真

SimPY是一个Python下的第三方库,可以方便的进行离散事件的仿真。仿真速度比较快。下面记录一下我的一点心得,不保证完全正确,供参考。

安装

$ pip install -U simpy

pycharm可以再File | Settings | Project: Simulation | Project Interpreter中添加

watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hlbGxvWkVY,size_16,color_FFFFFF,t_70

主要概念

Environment

Process

Event

Resource

SimPY使用Environment,Process,Event,Resource四大概念来进行离散事件的仿真。

Environment就是整体仿真所在的时间,主要用于提取时间。

Process就是仿真过程中的实体,如:顾客, 设备, 车辆等。 Process本质上也是一个event。源代码里面可以看到是继承Event的一个类。

Event是仿真中触发的事件,可以理解为一个定时器。当定时器到时时,触发事件。

Resource是仿真中的资源,如ATM机,服务器等。

官方示例:

>>> import simpy

>>>

>>> def clock(env, name, tick):

... while True:

... print(name, env.now)

... yield env.timeout(tick)

...

>>> env = simpy.Environment()

>>> env.process(clock(env, 'fast', 0.5))

>>> env.process(clock(env, 'slow', 1))

>>> env.run(until=2)

fast 0

slow 0

fast 0.5

slow 1

fast 1.0

fast 1.5

逻辑很简单,

1. 创建一个env

2. 以env为参数创建process, process有名字和参数,process内部使用生成器直接调用了超时事件。

3. 运行该env

深入原理

通过SimPY的源代码可以了解到,SimPY使用了一个heapq队列,这个队列中的元素是事件。Environment中对这个 队列进行调度,实际上是将事件压入队列中,environment中还有step方法,就是从队列中取出时间最小的一个事件(也就是时间点上最接近当前时间的下一个事件,使用heapq的heappop方法),然后运行这个事件的callback函数,一般就是Process。 因此仿真实际上是对一系列事件进行压入队列,按时间序弹出队列的过程。这样可以避免使用时间步长进行步进,时间步长步进的缺点就是太慢了。必须一个时间步长一个时间步长的挨个遍历过去,如果时间步长不合理的话,会有大量的计算时间上的浪费。

另外,为了语法上的优美易用,env中使用了Python的反射机制,将常用的几种事件,包括Process, Timeout, Anyof, Allof, Event都绑定为env的一种方法。 这个语法看上去很简单,但实现机制相对有点难以理解(我也只是了解是一种反射),只需要记住类似env.process, env.timeout, env.event, env.all_of, env.any_of的方法调用实际上都是声明了simpy.Process, simpy.Timeout等类的就可以了。详细实现在simpy.core.py中。

稍微复杂一点的例子:

"""

服务站示例

场景介绍:

一个有特定服务提供工作站,客户服务时长不一,工作机器数有限。

Client接受服务步骤:Client到达工作站,若有空闲的机器就立刻接受服务,如果没有,就等待直到其他机器空闲下来。

每个接受过服务的Client都有一个完成满意度(或者为进度)实时统计服务客户数和完成满意进度。

"""

import random

import simpy

# 可接受输入参数

RANDOM_SEED = 0 # 不设置

NUM_MACHINES = 2 # 可以同时处理的机器数(类似工作工位数)

TIME_CONSUMING = 5 # 单任务耗时 (可以设计成随机数)

TIME_INTERVAL = 5 # 来车的间隔时间约5分钟 (可以设计成随机数)

SIM_TIME = 1000 # 仿真总时间

CLIENT_NUMBER = 2 # 初始时已经占用机器数

class WorkStation(object):

"""

一个工作站,拥有特定数量的机器数。 一个客户首先申请服务。在对应服务时间完成后结束并离开工作站

"""

def __init__(self, env, num_machines, washtime):

self.env = env

self.machine = simpy.Resource(env, num_machines)

self.washtime = washtime

self.allClient = 0

self.accomplishClient = 0

def wash(self, car):

"""服务流程"""

yield self.env.timeout(random.randint(2, 10)) # 假设服务时间为随机数(2~10)

self.allClient += 1

per = random.randint(50, 99)

print("%s's 任务完成度:%d%%." % (car, per))

if per > 80:

self.accomplishClient += 1

print("工作站服务客户数:%d,"

"工作站服务达标率:%.2f。" % (self.allClient, float(self.accomplishClient) / float(self.allClient)))

def Client(env, name, cw):

"""

客户到达动作站接受服务,结束后离开

"""

print('%s 到达工作站 at %.2f.' % (name, env.now))

with cw.machine.request() as request:

yield request

print('%s 接受服务 at %.2f.' % (name, env.now))

yield env.process(cw.wash(name))

print('%s 离开服务站 at %.2f.' % (name, env.now))

def setup(env, num_machines, washtime, t_inter, clientNumber):

"""创建一个工作站,几个初始客户,然后持续有客户到达. 每隔t_inter - 2, t_inter + 3分钟(可以自定义)."""

# 创建工作站

workstation = WorkStation(env, num_machines, washtime)

# 创建clientNumber个初始客户

for i in range(clientNumber):

env.process(Client(env, 'Client_%d' % i, workstation))

# 在仿真过程中持续创建客户

while True:

yield env.timeout(random.randint(t_inter - 2, t_inter + 3)) # 3-8分钟

i += 1

env.process(Client(env, 'Client_%d' % i, workstation))

# 初始化并开始仿真任务

print('开始仿真')

# 初始化seed,指定数值的时候方正结果可以复现

random.seed()

# 创建一个环境并开始仿真

env = simpy.Environment()

env.process(setup(env, NUM_MACHINES, TIME_CONSUMING, TIME_INTERVAL, CLIENT_NUMBER))

# 开始执行!

env.run(until=SIM_TIME)

输出:

开始仿真

Client_0 到达工作站 at 0.00.

Client_1 到达工作站 at 0.00.

Client_0 接受服务 at 0.00.

Client_1 接受服务 at 0.00.

Client_2 到达工作站 at 3.00.

Client_0's 任务完成度:54%.

工作站服务客户数:1,工作站服务达标率:0.00。

Client_3 到达工作站 at 7.00.

Client_0 离开服务站 at 7.00.

Client_2 接受服务 at 7.00.

Client_1's 任务完成度:97%.

工作站服务客户数:2,工作站服务达标率:0.50。

.

.

.

Client_179 接受服务 at 986.00.

Client_178 离开服务站 at 986.00.

Client_180 到达工作站 at 989.00.

Client_180 接受服务 at 989.00.

Client_179's 任务完成度:89%.

工作站服务客户数:180,工作站服务达标率:0.36。

Client_179 离开服务站 at 993.00.

Client_181 到达工作站 at 995.00.

Client_181 接受服务 at 995.00.

Client_180's 任务完成度:96%.

工作站服务客户数:181,工作站服务达标率:0.36。

Client_180 离开服务站 at 997.00.

Process finished with exit code 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值