在Simpy模拟中,我怎样才能摆脱无限循环
In Simpy simulation, how can I escape from infinite loop
我在Simpy模拟中遇到死循环问题。
我的场景是:
完成分诊后,病人等待空床。
但是,如果没有空床,患者应等到有空床可用。
当患者使用床离开医院时,床会变成脏床。
当清洁工打扫干净时,脏床变成了一张空床。
收到清洁请求后开始清洁床工作。
我使用“商店”来管理床位
我觉得我在没有空床也没有脏床的情况下有一个无限循环。
我觉得...
- 添加队列(分类后)
- 从队列中,根据先进先出分配床位。
- 如果我们没有空床或脏床,我们应该等到有脏床可用。
但是,我不知道如何实现这个想法。
请帮我解决这个问题。
import simpy
import random
class Pre_Define:
warmup_period = 1440
sim_duration = 14400
number_of_runs = 3
class Patients:
def __init__(self, p_id):
self.id = p_id
self.bed_name = ""
self.admission_decision = ""
def admin_decision(self):
admin_decision_prob = random.uniform(0, 1)
if admin_decision_prob <= 0.7:
self.admission_decision = "DIS"
class Model:
def __init__(self, run_number):
self.env = simpy.Environment()
self.pt_counter = 0
self.tg = simpy.Resource(self.env, capacity = 4)
self.physician = simpy.Resource(self.env, capacity = 4)
self.bed_clean = simpy.Store(self.env, capacity = 77)
self.bed_dirty = simpy.Store(self.env, capacity = 77)
self.IU_bed = simpy.Resource(self.env, capacity = 50)
self.bed_cleaner = simpy.Resource(self.env, capacity = 2)
self.run_number = run_number
def generate_beds(self):
for i in range(77):
yield self.env.timeout(0)
yield self.bed_clean.put(f'bed{i}')
print(self.bed_clean.items)
def generate_pt_arrivals(self):
while True:
self.pt_counter += 1
pt = Patients(self.pt_counter)
yield self.env.timeout(1/7)
self.env.process(self.Process(pt))
def Process(self, Patients):
with self.tg.request() as req:
yield req
triage_service_time = random.expovariate(1.0/18)
yield self.env.timeout(triage_service_time)
if self.bed_clean.items != []:
get_empty_bed_name = yield self.bed_clean.get()
Patients.bed_name = get_empty_bed_name
elif self.bed_dirty.items != []:
get_dirty_bed_name = yield self.bed_dirty.get()
with self.bed_cleaner.request() as req:
yield req
yield self.env.timeout(50)
else:
print("NO BED, Should Wait!!")
no_bed = True
while no_bed:
#print("Waiting dirty bed")
if self.bed_dirty.items != []:
get_dirty_bed_name = yield self.bed_dirty.get()
print("Find dirty bed!")
with self.bed_cleaner.request() as req:
yield req
yield self.env.timeout(30)
Patients.bed_name = get_dirty_bed_name
no_bed = False
with self.physician.request() as req:
yield req
yield self.env.timeout(10)
Patients.admin_decision()
if Patients.admission_decision == "DIS":
with self.IU_bed.request() as req:
yield req
yield self.env.timeout(600)
get_dirty_bed_name = Patients.bed_name
yield self.bed_dirty.put(get_dirty_bed_name)
else:
get_dirty_bed_name = Patients.bed_name
yield self.bed_dirty.put(get_dirty_bed_name)
def run(self):
self.env.process(self.generate_pt_arrivals())
self.env.process(self.generate_beds())
self.env.run(until = Pre_Define.warmup_period + Pre_Define.sim_duration)
for run in range(Pre_Define.number_of_runs):
run_model = Model(run)
run_model.run()
print()
所以您的想法是正确的,您可以使用两个商店来跟踪脏床和干净床。诀窍是同时请求一张干净的床和一张脏的床,并丢弃您不使用的请求。
所以我做的最大改变是要求一张干净的床和一张脏床,并使用 env.any_of() 给我第一个满足的请求。请注意,这两个请求都可能得到满足。由于我提出了两个请求,这意味着我需要取消我不使用的请求,或者如果已满,return 将未使用的床放回其队列。我做的另一件事是为清洁工制作一个单独的过程。这意味着病人和清洁工都将争夺肮脏的床位。
"""
Quick sim model of beds in a hosptial triage
beds have two states, clean and dirty
When a patient arrives they are assigned to a empty bed
If no beds are avail then the patient wait for first empty bed
If there is both a clean bed and a empty bed, the clean bed will be assigned
When the patient leaves triage the bed state is dirty.
empty dirty beads are queued to be clean, after cleaning bed state is clean
After being triaged, a patient is either admited or discharged.
If the patient is admitted, then they wait for a IU bed befor the triage bed is empty
Programmer: Michael R. Gibbs
"""
import simpy
import random
TRIAGE_TIME = 30
BED_CLEAN_TIME = 20
class Patient():
"""
has id to track patient progress
and bed when assigned to a bed
"""
next_id = 1
@classmethod
def get_next_id(cls):
id = cls.next_id
cls.next_id += 1
return id
def __init__(self):
self.id = self.get_next_id()
self.bed = None
class Bed():
"""
has id to track patient progress
and bed when assigned to a bed
"""
next_id = 1
@classmethod
def get_next_id(cls):
id = cls.next_id
cls.next_id += 1
return id
def __init__(self):
self.id = self.get_next_id()
self.bed_state = 'Clean'
def clean_beds(env, dirty_bed_q, clean_bed_q):
"""
Sim process for cleaning dirty beds from
the dirty queue, and putting the clean
beds into clean queue
A instance shoud be started for each cleaner
"""
while True:
bed = yield dirty_bed_q.get()
print(f'{env.now:.2f} bed {bed.id} is being cleaned')
# clean
yield env.timeout(BED_CLEAN_TIME)
bed.bed_state = "Clean"
clean_bed_q.put(bed)
print(f'{env.now:.2f} bed {bed.id} is clean')
def triage(env, pat, clean_bed_q, dirty_bed_q, ui_bed_q):
"""
models the patients life cycle in triage
stepss are:
get bed (clean perfered)
get triaged
leave
if addmited leaving is blocked until a ui bed is found
"""
# get bed
clean_req = clean_bed_q.get()
dirty_req = dirty_bed_q.get()
print(f'{env.now:.2f} patient {pat.id} has arrived')
fired = yield env.any_of([clean_req, dirty_req])
# see if we got a clean or dirty or both
if clean_req in fired:
# got a clean bead
pat.bed = fired[clean_req]
# need to deal with the dirty req
if dirty_req in fired:
# got two beds but dirty back
dirty_bed_q.put(fired[dirty_req])
else:
# stil need to cancel req
dirty_req.cancel()
else:
# we have a dirty bed
pat.bed = fired[dirty_req]
# need to deal with the dirty req
if clean_req in fired:
# got two beds but dirty back
clean_bed_q.put(fired[clean_req])
else:
# stil need to cancel req
clean_req.cancel()
print(f'{env.now:.2f} {pat.bed.bed_state} bed {pat.bed.id} is occupied and dirty with patient {pat.id}')
pat.bed.bed_state = 'Dirty'
# triage
yield env.timeout(TRIAGE_TIME)
admit = (random.uniform(0,1) < 0.7)
if admit:
# need to get a IU bed before
# patient gives up triage bed
print(f'{env.now:.2f} patient {pat.id} is being admitted')
ui_req = ui_bed_q.request()
yield ui_req
print(f'{env.now:.2f} patient {pat.id} got iu bed')
# patient leaves triage
# give up dirty bed
dirty_bed_q.put(pat.bed)
print(f'{env.now:.2f} bed {pat.bed.id} is empty and patient {pat.id} has left')
def gen_pats(env, clean_bed_q, dirty_bed_q, iu_bed_q):
"""
creates the arriving patients
"""
while True:
yield env.timeout(random.uniform(1,8))
pat = Patient()
# not each patient gets their own process
# so if one patient blocks while waiting for a iu bed, it does
# not block the other patients
env.process(triage(env, pat, clean_bed_q, dirty_bed_q, iu_bed_q))
def model():
env = simpy.Environment()
# make queues
clean_bed_q = simpy.Store(env)
dirty_bed_q = simpy.Store(env)
iu_bed_q = simpy.Resource(env,capacity=5)
clean_bed_q.items = [Bed() for _ in range(10)]
# start generating patients
env.process(gen_pats(env, clean_bed_q, dirty_bed_q, iu_bed_q))
# star up cleaners
for _ in range(2):
env.process(clean_beds(env, dirty_bed_q, clean_bed_q))
env.run(until=100)
print('simulation finish')
model()
我在Simpy模拟中遇到死循环问题。
我的场景是: 完成分诊后,病人等待空床。 但是,如果没有空床,患者应等到有空床可用。 当患者使用床离开医院时,床会变成脏床。 当清洁工打扫干净时,脏床变成了一张空床。 收到清洁请求后开始清洁床工作。
我使用“商店”来管理床位 我觉得我在没有空床也没有脏床的情况下有一个无限循环。
我觉得...
- 添加队列(分类后)
- 从队列中,根据先进先出分配床位。
- 如果我们没有空床或脏床,我们应该等到有脏床可用。
但是,我不知道如何实现这个想法。 请帮我解决这个问题。
import simpy
import random
class Pre_Define:
warmup_period = 1440
sim_duration = 14400
number_of_runs = 3
class Patients:
def __init__(self, p_id):
self.id = p_id
self.bed_name = ""
self.admission_decision = ""
def admin_decision(self):
admin_decision_prob = random.uniform(0, 1)
if admin_decision_prob <= 0.7:
self.admission_decision = "DIS"
class Model:
def __init__(self, run_number):
self.env = simpy.Environment()
self.pt_counter = 0
self.tg = simpy.Resource(self.env, capacity = 4)
self.physician = simpy.Resource(self.env, capacity = 4)
self.bed_clean = simpy.Store(self.env, capacity = 77)
self.bed_dirty = simpy.Store(self.env, capacity = 77)
self.IU_bed = simpy.Resource(self.env, capacity = 50)
self.bed_cleaner = simpy.Resource(self.env, capacity = 2)
self.run_number = run_number
def generate_beds(self):
for i in range(77):
yield self.env.timeout(0)
yield self.bed_clean.put(f'bed{i}')
print(self.bed_clean.items)
def generate_pt_arrivals(self):
while True:
self.pt_counter += 1
pt = Patients(self.pt_counter)
yield self.env.timeout(1/7)
self.env.process(self.Process(pt))
def Process(self, Patients):
with self.tg.request() as req:
yield req
triage_service_time = random.expovariate(1.0/18)
yield self.env.timeout(triage_service_time)
if self.bed_clean.items != []:
get_empty_bed_name = yield self.bed_clean.get()
Patients.bed_name = get_empty_bed_name
elif self.bed_dirty.items != []:
get_dirty_bed_name = yield self.bed_dirty.get()
with self.bed_cleaner.request() as req:
yield req
yield self.env.timeout(50)
else:
print("NO BED, Should Wait!!")
no_bed = True
while no_bed:
#print("Waiting dirty bed")
if self.bed_dirty.items != []:
get_dirty_bed_name = yield self.bed_dirty.get()
print("Find dirty bed!")
with self.bed_cleaner.request() as req:
yield req
yield self.env.timeout(30)
Patients.bed_name = get_dirty_bed_name
no_bed = False
with self.physician.request() as req:
yield req
yield self.env.timeout(10)
Patients.admin_decision()
if Patients.admission_decision == "DIS":
with self.IU_bed.request() as req:
yield req
yield self.env.timeout(600)
get_dirty_bed_name = Patients.bed_name
yield self.bed_dirty.put(get_dirty_bed_name)
else:
get_dirty_bed_name = Patients.bed_name
yield self.bed_dirty.put(get_dirty_bed_name)
def run(self):
self.env.process(self.generate_pt_arrivals())
self.env.process(self.generate_beds())
self.env.run(until = Pre_Define.warmup_period + Pre_Define.sim_duration)
for run in range(Pre_Define.number_of_runs):
run_model = Model(run)
run_model.run()
print()
所以您的想法是正确的,您可以使用两个商店来跟踪脏床和干净床。诀窍是同时请求一张干净的床和一张脏的床,并丢弃您不使用的请求。
所以我做的最大改变是要求一张干净的床和一张脏床,并使用 env.any_of() 给我第一个满足的请求。请注意,这两个请求都可能得到满足。由于我提出了两个请求,这意味着我需要取消我不使用的请求,或者如果已满,return 将未使用的床放回其队列。我做的另一件事是为清洁工制作一个单独的过程。这意味着病人和清洁工都将争夺肮脏的床位。
"""
Quick sim model of beds in a hosptial triage
beds have two states, clean and dirty
When a patient arrives they are assigned to a empty bed
If no beds are avail then the patient wait for first empty bed
If there is both a clean bed and a empty bed, the clean bed will be assigned
When the patient leaves triage the bed state is dirty.
empty dirty beads are queued to be clean, after cleaning bed state is clean
After being triaged, a patient is either admited or discharged.
If the patient is admitted, then they wait for a IU bed befor the triage bed is empty
Programmer: Michael R. Gibbs
"""
import simpy
import random
TRIAGE_TIME = 30
BED_CLEAN_TIME = 20
class Patient():
"""
has id to track patient progress
and bed when assigned to a bed
"""
next_id = 1
@classmethod
def get_next_id(cls):
id = cls.next_id
cls.next_id += 1
return id
def __init__(self):
self.id = self.get_next_id()
self.bed = None
class Bed():
"""
has id to track patient progress
and bed when assigned to a bed
"""
next_id = 1
@classmethod
def get_next_id(cls):
id = cls.next_id
cls.next_id += 1
return id
def __init__(self):
self.id = self.get_next_id()
self.bed_state = 'Clean'
def clean_beds(env, dirty_bed_q, clean_bed_q):
"""
Sim process for cleaning dirty beds from
the dirty queue, and putting the clean
beds into clean queue
A instance shoud be started for each cleaner
"""
while True:
bed = yield dirty_bed_q.get()
print(f'{env.now:.2f} bed {bed.id} is being cleaned')
# clean
yield env.timeout(BED_CLEAN_TIME)
bed.bed_state = "Clean"
clean_bed_q.put(bed)
print(f'{env.now:.2f} bed {bed.id} is clean')
def triage(env, pat, clean_bed_q, dirty_bed_q, ui_bed_q):
"""
models the patients life cycle in triage
stepss are:
get bed (clean perfered)
get triaged
leave
if addmited leaving is blocked until a ui bed is found
"""
# get bed
clean_req = clean_bed_q.get()
dirty_req = dirty_bed_q.get()
print(f'{env.now:.2f} patient {pat.id} has arrived')
fired = yield env.any_of([clean_req, dirty_req])
# see if we got a clean or dirty or both
if clean_req in fired:
# got a clean bead
pat.bed = fired[clean_req]
# need to deal with the dirty req
if dirty_req in fired:
# got two beds but dirty back
dirty_bed_q.put(fired[dirty_req])
else:
# stil need to cancel req
dirty_req.cancel()
else:
# we have a dirty bed
pat.bed = fired[dirty_req]
# need to deal with the dirty req
if clean_req in fired:
# got two beds but dirty back
clean_bed_q.put(fired[clean_req])
else:
# stil need to cancel req
clean_req.cancel()
print(f'{env.now:.2f} {pat.bed.bed_state} bed {pat.bed.id} is occupied and dirty with patient {pat.id}')
pat.bed.bed_state = 'Dirty'
# triage
yield env.timeout(TRIAGE_TIME)
admit = (random.uniform(0,1) < 0.7)
if admit:
# need to get a IU bed before
# patient gives up triage bed
print(f'{env.now:.2f} patient {pat.id} is being admitted')
ui_req = ui_bed_q.request()
yield ui_req
print(f'{env.now:.2f} patient {pat.id} got iu bed')
# patient leaves triage
# give up dirty bed
dirty_bed_q.put(pat.bed)
print(f'{env.now:.2f} bed {pat.bed.id} is empty and patient {pat.id} has left')
def gen_pats(env, clean_bed_q, dirty_bed_q, iu_bed_q):
"""
creates the arriving patients
"""
while True:
yield env.timeout(random.uniform(1,8))
pat = Patient()
# not each patient gets their own process
# so if one patient blocks while waiting for a iu bed, it does
# not block the other patients
env.process(triage(env, pat, clean_bed_q, dirty_bed_q, iu_bed_q))
def model():
env = simpy.Environment()
# make queues
clean_bed_q = simpy.Store(env)
dirty_bed_q = simpy.Store(env)
iu_bed_q = simpy.Resource(env,capacity=5)
clean_bed_q.items = [Bed() for _ in range(10)]
# start generating patients
env.process(gen_pats(env, clean_bed_q, dirty_bed_q, iu_bed_q))
# star up cleaners
for _ in range(2):
env.process(clean_beds(env, dirty_bed_q, clean_bed_q))
env.run(until=100)
print('simulation finish')
model()