Запрос первого доступного ресурса в Simpy Python
Я хочу создать имитационную модель, которая имитирует банк с 3-мя количеством счетчиков. Я хочу, чтобы была одна очередь для клиентов, и если какой-либо из счетчиков доступен, он будет обслуживать счетчик в течение некоторого времени. Каждый счетчик - это собственный простой ресурс (я не могу сделать один ресурс емкостью 3), и мне нужно знать, какой счетчик обслуживает клиента. У меня проблемы с реализацией этого.
Я нашел эту статью, которая, кажется, о той же самой проблеме, но все еще не знает точную реализацию http://comments.gmane.org/gmane.comp.python.simpy.user/1754
Я предполагаю, что мне нужен выход simpy.AnyOf (env, list_of_resources), чтобы запросить первый доступный счетчик, но я не могу понять, как правильно его настроить, а также, если одновременно становится доступно более одного ресурса, я Я хочу выбрать способ проверки, чтобы я мог выбрать счетчик, к которому лучше обратиться покупателю.
Я использую Python версии 2.7, Simpy версии 3.0.4
РЕДАКТИРОВАТЬ Добавление кода, который показывает, что я пытаюсь сделать и как это не работает прямо сейчас.
import simpy
import random
LENGTH_SIM = 200.0
class Customer(object):
def __init__(self, arrive_time, num):
self.arrive_time = arrive_time
self.start_service_time = -1.0
self.finish_service_time = -1.0
self.served_by = -1.0
self.num = num
def print_attributes(self):
format_string = "#%3d Arrive: %6.1f Start Service: %6.1f "\
+ " End Service: %6.1f" + " Served By: %3d"
print format_string %(self.num, self.arrive_time,
self.start_service_time,
self.finish_service_time, self.served_by)
class Counter(object):
def __init__(self, number):
self.number = number
self.name = "Counter " + str(number)
self.start_times = []
self.end_times = []
class Bank(object):
def __init__(self, env, num_counters):
self.counters = [Counter(x+1) for x in range(num_counters)]
self.num_counters = num_counters
self.counters_resources = [simpy.Resource(env, capacity=1)
for x in range(num_counters)]
def generate_customers(env, customers):
count = 1
while 1:
wait_time = random.randint(8, 12)
yield env.timeout(wait_time)
customers.append(Customer(env.now, count))
print "Generated Customer: ", count
count += 1
def select_counter(env, bank):
'''choose a counter for the customer'''
for x in range(len(bank.counters)):
if bank.counters_resources[len(bank.counters) - 1 - x].count == 0:
print "Counter Selected: ", len(bank.counters) - 1 - x
print bank.counters[len(bank.counters) - 1 - x].number
print bank.counters_resources[len(bank.counters) - 1 - x].users
return len(bank.counters) - 1 - x
return -2.0
def gen_service_time():
return random.random() * 20.0 + 21.0
def handle_customer(env, bank, customer, customers, num_process):
'''handles customer'''
print "Process ", num_process, " started at:", env.now
counter = select_counter(env, bank)
print "Process ", num_process, " after counter select:", env.now
if counter != -2.0:
with bank.counters_resources[counter].request() as req:
yield req
print "Process ", num_process, "Time", env.now, "In if"
bank.counters[counter].start_times.append(env.now)
service_time = gen_service_time()
customer.start_service_time = env.now
customer.finish_service_time = env.now + service_time
bank.counters[counter].end_times.append(env.now + service_time)
customer.served_by = counter + 1
yield env.timeout(service_time)
else:
reqs = []
for x in range(len(bank.counters)):
reqs.append(bank.counters_resources[x].request())
counter_used = yield simpy.events.AnyOf(env, reqs)
for x in range(len(reqs)):
if counter_used.keys()[0] != reqs[x]:
print "True"
bank.counters_resources[x].release(reqs[x])
print "Process ", num_process, "Time", env.now, "In else"
bank.counters[0].start_times.append(env.now)
service_time = gen_service_time()
customer.start_service_time = env.now
customer.finish_service_time = env.now + service_time
bank.counters[0].end_times.append(env.now + service_time)
customer.served_by = 1
yield env.timeout(service_time)
for x in range(len(reqs)):
## if counter_used.keys()[0] == reqs[x]:
if 1:
bank.counters_resources[x].release(reqs[x])
def run_bank(env, bank, customers):
while 1:
min_time = -1.0
min_customer = -1.0
for x in xrange(len(customers)):
if customers[x].arrive_time < min_time or min_time == -1.0:
if customers[x].arrive_time > env.now:
min_time = customers[x].arrive_time
min_customer = x
else:
continue
if min_time == -1.0:
yield env.timeout(LENGTH_SIM - env.now)
yield env.timeout(min_time - env.now)
print "Calling Process: ", min_customer, "At time:", env.now
env.process(handle_customer(env,bank,customers[min_customer],customers,
min_customer + 1))
def run_sim():
env = simpy.Environment()
customers = []
env.process(generate_customers(env, customers))
env.run(until=LENGTH_SIM)
env2 = simpy.Environment()
bank = Bank(env2, 3)
env2.process(run_bank(env2, bank, customers))
env2.run(until = LENGTH_SIM)
for x in range(len(customers)):
customers[x].print_attributes()
if __name__ == '__main__':
run_sim()
2 ответа
Мне удалось решить это самостоятельно, единственное, чего я не понимаю, это то, что делают различные аргументы метода отмены (я просто установил их все как None, и это работает, я не уверен, где есть документация о том, что они кроме их имени). Фиксированный код выглядит следующим образом (соответствующей частью является предложение else в функции handle_customer:
import simpy
import random
LENGTH_SIM = 100.0
class Customer(object):
def __init__(self, arrive_time, num):
self.arrive_time = arrive_time
self.start_service_time = -1.0
self.finish_service_time = -1.0
self.served_by = -1.0
self.num = num
def print_attributes(self):
format_string = "#%3d Arrive: %6.1f Start Service: %6.1f "\
+ " End Service: %6.1f" + " Served By: %3d"
print format_string %(self.num, self.arrive_time,
self.start_service_time,
self.finish_service_time, self.served_by)
class Counter(object):
def __init__(self, number):
self.number = number
self.name = "Counter " + str(number)
self.start_times = []
self.end_times = []
class Bank(object):
def __init__(self, env, num_counters):
self.counters = [Counter(x+1) for x in range(num_counters)]
self.num_counters = num_counters
self.counters_resources = [simpy.Resource(env, capacity=1)
for x in range(num_counters)]
def generate_customers(env, customers):
count = 1
while 1:
## wait_time = random.randint(8, 12)
wait_time = 2
yield env.timeout(wait_time)
customers.append(Customer(env.now, count))
print "Generated Customer: ", count
count += 1
def select_counter(env, bank):
'''choose a counter for the customer'''
for x in range(len(bank.counters)):
if bank.counters_resources[len(bank.counters) - 1 - x].count == 0 and\
bank.counters_resources[len(bank.counters) - 1 - x].queue == []:
print "Counter Selected: ", len(bank.counters) - 1 - x
return len(bank.counters) - 1 - x
return -2.0
def gen_service_time():
## return random.random() * 20.0 + 19.0
return random.randint(4, 8)
def wait_til_available(env, bank, temp_list):
while 1:
yield env.timeout(0.0001)
for x in range(len(bank.counters)):
if bank.counters_resources[x].count == 0:
req = bank.counters_resources[x].request()
temp_list[0] = x
temp_list[1] = req
return
def handle_customer(env, bank, customer, customers, num_process):
'''handles customer'''
print "Process ", num_process, " started at:", env.now
counter = select_counter(env, bank)
if counter != -2.0:
with bank.counters_resources[counter].request() as req:
yield req
bank.counters[counter].start_times.append(env.now)
service_time = gen_service_time()
customer.start_service_time = env.now
customer.finish_service_time = env.now + service_time
bank.counters[counter].end_times.append(env.now + service_time)
customer.served_by = counter + 1
yield env.timeout(service_time)
else:
reqs = []
got_counter = 0
for x in range(len(bank.counters)):
reqs.append(bank.counters_resources[x].request())
good_req = yield simpy.events.AnyOf(env, reqs)
req = good_req.keys()[0]
for x in range(len(bank.counters)):
if req != reqs[x]:
bank.counters_resources[x].release(reqs[x])
reqs[x].cancel(None, None, None)
else:
got_counter = x
bank.counters[got_counter].start_times.append(env.now)
service_time = gen_service_time()
customer.start_service_time = env.now
customer.finish_service_time = env.now + service_time
bank.counters[got_counter].end_times.append(env.now + service_time)
customer.served_by = got_counter + 1
yield env.timeout(service_time)
print "Process ", num_process, " finished at:", env.now
bank.counters_resources[got_counter].release(req)
def run_bank(env, bank, customers):
while 1:
min_time = -1.0
min_customer = -1.0
for x in xrange(len(customers)):
if customers[x].arrive_time < min_time or min_time == -1.0:
if customers[x].arrive_time > env.now:
min_time = customers[x].arrive_time
min_customer = x
else:
continue
if min_time == -1.0:
yield env.timeout(LENGTH_SIM - env.now)
yield env.timeout(min_time - env.now)
print "Calling Process: ", min_customer+1, "At time:", env.now
env.process(handle_customer(env,bank,customers[min_customer],customers,
min_customer + 1))
def run_sim():
env = simpy.Environment()
customers = []
env.process(generate_customers(env, customers))
env.run(until=LENGTH_SIM)
env2 = simpy.Environment()
bank = Bank(env2, 3)
env2.process(run_bank(env2, bank, customers))
env2.run(until = LENGTH_SIM)
for x in range(len(customers)):
customers[x].print_attributes()
if __name__ == '__main__':
run_sim()
Если вы действительно не можете использовать обычный ресурс с емкостью 3, возможно, Store поможет вам. В магазине хранятся объекты счетчиков, которые вы можете запросить. Каждый счетчик имеет свою индивидуальность и может, например, отслеживать количество использований. После того, как клиент сделан, он должен положить счетчик обратно в магазин:
import simpy
class Counter:
usages = 0
def customer(env, counters):
counter = yield counters.get()
yield env.timeout(1)
counter.usages += 1
yield counters.put(counter)
env = simpy.Environment()
counters = simpy.Store(env, capacity=3)
counters.items = [Counter() for i in range(counters.capacity)]
for i in range(10):
env.process(customer(env, counters))
env.run()
for counter in counters.items:
print(counter.usages)