python语言例子_【Python】SimPy的使用示例-Go语言中文社区
使用SimPY進(jìn)行離散事件仿真
SimPY是一個(gè)Python下的第三方庫(kù),可以方便的進(jìn)行離散事件的仿真。仿真速度比較快。下面記錄一下我的一點(diǎn)心得,不保證完全正確,供參考。
安裝
$ pip install -U simpy
pycharm可以再File | Settings | Project: Simulation | Project Interpreter中添加
主要概念
Environment
Process
Event
Resource
SimPY使用Environment,Process,Event,Resource四大概念來(lái)進(jìn)行離散事件的仿真。
Environment就是整體仿真所在的時(shí)間,主要用于提取時(shí)間。
Process就是仿真過(guò)程中的實(shí)體,如:顧客, 設(shè)備, 車(chē)輛等。 Process本質(zhì)上也是一個(gè)event。源代碼里面可以看到是繼承Event的一個(gè)類(lèi)。
Event是仿真中觸發(fā)的事件,可以理解為一個(gè)定時(shí)器。當(dāng)定時(shí)器到時(shí)時(shí),觸發(fā)事件。
Resource是仿真中的資源,如ATM機(jī),服務(wù)器等。
官方示例:
>>> 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
邏輯很簡(jiǎn)單,
1. 創(chuàng)建一個(gè)env
2. 以env為參數(shù)創(chuàng)建process, process有名字和參數(shù),process內(nèi)部使用生成器直接調(diào)用了超時(shí)事件。
3. 運(yùn)行該env
深入原理
通過(guò)SimPY的源代碼可以了解到,SimPY使用了一個(gè)heapq隊(duì)列,這個(gè)隊(duì)列中的元素是事件。Environment中對(duì)這個(gè) 隊(duì)列進(jìn)行調(diào)度,實(shí)際上是將事件壓入隊(duì)列中,environment中還有step方法,就是從隊(duì)列中取出時(shí)間最小的一個(gè)事件(也就是時(shí)間點(diǎn)上最接近當(dāng)前時(shí)間的下一個(gè)事件,使用heapq的heappop方法),然后運(yùn)行這個(gè)事件的callback函數(shù),一般就是Process。 因此仿真實(shí)際上是對(duì)一系列事件進(jìn)行壓入隊(duì)列,按時(shí)間序彈出隊(duì)列的過(guò)程。這樣可以避免使用時(shí)間步長(zhǎng)進(jìn)行步進(jìn),時(shí)間步長(zhǎng)步進(jìn)的缺點(diǎn)就是太慢了。必須一個(gè)時(shí)間步長(zhǎng)一個(gè)時(shí)間步長(zhǎng)的挨個(gè)遍歷過(guò)去,如果時(shí)間步長(zhǎng)不合理的話(huà),會(huì)有大量的計(jì)算時(shí)間上的浪費(fèi)。
另外,為了語(yǔ)法上的優(yōu)美易用,env中使用了Python的反射機(jī)制,將常用的幾種事件,包括Process, Timeout, Anyof, Allof, Event都綁定為env的一種方法。 這個(gè)語(yǔ)法看上去很簡(jiǎn)單,但實(shí)現(xiàn)機(jī)制相對(duì)有點(diǎn)難以理解(我也只是了解是一種反射),只需要記住類(lèi)似env.process, env.timeout, env.event, env.all_of, env.any_of的方法調(diào)用實(shí)際上都是聲明了simpy.Process, simpy.Timeout等類(lèi)的就可以了。詳細(xì)實(shí)現(xiàn)在simpy.core.py中。
稍微復(fù)雜一點(diǎn)的例子:
"""
服務(wù)站示例
場(chǎng)景介紹:
一個(gè)有特定服務(wù)提供工作站,客戶(hù)服務(wù)時(shí)長(zhǎng)不一,工作機(jī)器數(shù)有限。
Client接受服務(wù)步驟:Client到達(dá)工作站,若有空閑的機(jī)器就立刻接受服務(wù),如果沒(méi)有,就等待直到其他機(jī)器空閑下來(lái)。
每個(gè)接受過(guò)服務(wù)的Client都有一個(gè)完成滿(mǎn)意度(或者為進(jìn)度)實(shí)時(shí)統(tǒng)計(jì)服務(wù)客戶(hù)數(shù)和完成滿(mǎn)意進(jìn)度。
"""
import random
import simpy
# 可接受輸入?yún)?shù)
RANDOM_SEED = 0 # 不設(shè)置
NUM_MACHINES = 2 # 可以同時(shí)處理的機(jī)器數(shù)(類(lèi)似工作工位數(shù))
TIME_CONSUMING = 5 # 單任務(wù)耗時(shí) (可以設(shè)計(jì)成隨機(jī)數(shù))
TIME_INTERVAL = 5 # 來(lái)車(chē)的間隔時(shí)間約5分鐘 (可以設(shè)計(jì)成隨機(jī)數(shù))
SIM_TIME = 1000 # 仿真總時(shí)間
CLIENT_NUMBER = 2 # 初始時(shí)已經(jīng)占用機(jī)器數(shù)
class WorkStation(object):
"""
一個(gè)工作站,擁有特定數(shù)量的機(jī)器數(shù)。 一個(gè)客戶(hù)首先申請(qǐng)服務(wù)。在對(duì)應(yīng)服務(wù)時(shí)間完成后結(jié)束并離開(kāi)工作站
"""
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):
"""服務(wù)流程"""
yield self.env.timeout(random.randint(2, 10)) # 假設(shè)服務(wù)時(shí)間為隨機(jī)數(shù)(2~10)
self.allClient += 1
per = random.randint(50, 99)
print("%s's 任務(wù)完成度:%d%%." % (car, per))
if per > 80:
self.accomplishClient += 1
print("工作站服務(wù)客戶(hù)數(shù):%d,"
"工作站服務(wù)達(dá)標(biāo)率:%.2f。" % (self.allClient, float(self.accomplishClient) / float(self.allClient)))
def Client(env, name, cw):
"""
客戶(hù)到達(dá)動(dòng)作站接受服務(wù),結(jié)束后離開(kāi)
"""
print('%s 到達(dá)工作站 at %.2f.' % (name, env.now))
with cw.machine.request() as request:
yield request
print('%s 接受服務(wù) at %.2f.' % (name, env.now))
yield env.process(cw.wash(name))
print('%s 離開(kāi)服務(wù)站 at %.2f.' % (name, env.now))
def setup(env, num_machines, washtime, t_inter, clientNumber):
"""創(chuàng)建一個(gè)工作站,幾個(gè)初始客戶(hù),然后持續(xù)有客戶(hù)到達(dá). 每隔t_inter - 2, t_inter + 3分鐘(可以自定義)."""
# 創(chuàng)建工作站
workstation = WorkStation(env, num_machines, washtime)
# 創(chuàng)建clientNumber個(gè)初始客戶(hù)
for i in range(clientNumber):
env.process(Client(env, 'Client_%d' % i, workstation))
# 在仿真過(guò)程中持續(xù)創(chuàng)建客戶(hù)
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))
# 初始化并開(kāi)始仿真任務(wù)
print('開(kāi)始仿真')
# 初始化seed,指定數(shù)值的時(shí)候方正結(jié)果可以復(fù)現(xiàn)
random.seed()
# 創(chuàng)建一個(gè)環(huán)境并開(kāi)始仿真
env = simpy.Environment()
env.process(setup(env, NUM_MACHINES, TIME_CONSUMING, TIME_INTERVAL, CLIENT_NUMBER))
# 開(kāi)始執(zhí)行!
env.run(until=SIM_TIME)
輸出:
開(kāi)始仿真
Client_0 到達(dá)工作站 at 0.00.
Client_1 到達(dá)工作站 at 0.00.
Client_0 接受服務(wù) at 0.00.
Client_1 接受服務(wù) at 0.00.
Client_2 到達(dá)工作站 at 3.00.
Client_0's 任務(wù)完成度:54%.
工作站服務(wù)客戶(hù)數(shù):1,工作站服務(wù)達(dá)標(biāo)率:0.00。
Client_3 到達(dá)工作站 at 7.00.
Client_0 離開(kāi)服務(wù)站 at 7.00.
Client_2 接受服務(wù) at 7.00.
Client_1's 任務(wù)完成度:97%.
工作站服務(wù)客戶(hù)數(shù):2,工作站服務(wù)達(dá)標(biāo)率:0.50。
.
.
.
Client_179 接受服務(wù) at 986.00.
Client_178 離開(kāi)服務(wù)站 at 986.00.
Client_180 到達(dá)工作站 at 989.00.
Client_180 接受服務(wù) at 989.00.
Client_179's 任務(wù)完成度:89%.
工作站服務(wù)客戶(hù)數(shù):180,工作站服務(wù)達(dá)標(biāo)率:0.36。
Client_179 離開(kāi)服務(wù)站 at 993.00.
Client_181 到達(dá)工作站 at 995.00.
Client_181 接受服務(wù) at 995.00.
Client_180's 任務(wù)完成度:96%.
工作站服務(wù)客戶(hù)數(shù):181,工作站服務(wù)達(dá)標(biāo)率:0.36。
Client_180 離開(kāi)服務(wù)站 at 997.00.
Process finished with exit code 0
總結(jié)
以上是生活随笔為你收集整理的python语言例子_【Python】SimPy的使用示例-Go语言中文社区的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 小爱音响调用php接口_PHP调用语音合
- 下一篇: caged系统pdf_建筑行业单词中英文