Simpy: одновременно освободить ресурс при выделении нового ресурса
Я упростил версию проблемы, которую я пытаюсь смоделировать, где я использую Simpy для описания движения путешественников по пути.
Путь представлен коллекцией Node()
объекты, где каждый узел содержит Simpy.Resource
, Каждый узел подключен к следующему узлу в пути connected_to
приписывать. В примере кода я создал список из 10 узлов, где каждый узел в списке связан с предыдущим узлом в списке.
Когда путешественник (представлен Occupier()
объект) создается ресурс узла. Затем путешественник перемещается по узлам, делая шаг только при наличии следующего узла. Моя цель состоит в том, чтобы путешественник одновременно выделил свой конечный узел и освободил узел, где он был ранее расположен.
import simpy
class Node(object):
def __init__(self, env):
self.env = env
self.resource = simpy.Resource(self.env)
self.up_connection = None
self.travel_delay = 5
class Occupier(object):
def __init__(self, env):
self.env = env
self.location = None
self.destination = None
self.requests = []
def travel(self, instantiation_loc):
self.requests.append(instantiation_loc.resource.request())
yield(self.requests[-1])
self.location = instantiation_loc
self.destination = instantiation_loc.up_connection
yield self.env.timeout(self.location.travel_delay)
node_occupancy(nodes)
while self.destination.up_connection != None:
self.requests.append(self.destination.resource.request())
yield self.requests[-1]
self.location.resource.release(self.requests[0])
self.requests.pop(0)
self.location = self.destination
self.destination = self.location.up_connection
yield self.env.timeout(self.location.travel_delay)
node_occupancy(nodes)
def node_occupancy(nodes):
print([node.resource.count for node in nodes])
env = simpy.Environment()
nodes = [Node(env) for i in range(10)]
for i in range(len(nodes) - 1):
nodes[i].up_connection = nodes[i + 1]
env.process(Occupier(env).travel(nodes[0]))
env.run()
Если я запускаю приведенный выше код с одним путешественником, он, кажется, работает нормально, давая следующий вывод:
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]
Однако, если создать экземпляр второго путешественника, вы увидите, что есть моменты времени, когда один путешественник занимает два ресурса, когда он должен занимать только один:
env.process(Occupier(env).travel(nodes[3]))
env.process(Occupier(env).travel(nodes[0]))
соответствующий вывод:
[1, 0, 0, 1, 0, 0, 0, 0, 0, 0]
[1, 0, 0, 1, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 1, 1, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 1, 0, 0, 0, 0]
[0, 0, 1, 0, 0, 1, 1, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 1, 0, 0, 0]
[0, 0, 0, 1, 0, 0, 1, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 1, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 1, 1, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 1, 0, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 1, 0, 1, 0]
[0, 0, 0, 0, 0, 0, 0, 1, 1, 0]
Для моего моделирования важно, чтобы путешественник занимал только один ресурс, так как атрибуты узлов часто изменяются на основе этого.
Есть ли способ предотвратить такое поведение, когда путешественник никогда не занимает более одного ресурса? т.е. ресурс освобождается одновременно, когда путешественнику выделяется новый ресурс
1 ответ
На самом деле ваша модель работает правильно.
Попробуй добавить в функцию node_ocupacy
текущее время выполнения и некоторые маркеры для идентификации текущего этапа моделирования:
def node_occupancy(nodes, node, case):
print(env.now, node, case, [node.resource.count for node in nodes])
Кроме того, я внес некоторые изменения, чтобы увидеть лучший журнал симуляции:
def travel(self, instantiation_loc, loc):
self.requests.append(instantiation_loc.resource.request())
yield(self.requests[-1])
self.location = instantiation_loc
self.destination = instantiation_loc.up_connection
yield self.env.timeout(self.location.travel_delay)
node_occupancy(nodes, loc, 1)
while self.destination.up_connection != None:
self.requests.append(self.destination.resource.request())
node_occupancy(nodes, loc, 2)
yield self.requests[-1]
node_occupancy(nodes, loc, 3)
self.location.resource.release(self.requests[0])
node_occupancy(nodes, loc, 4)
self.requests.pop(0)
self.location = self.destination
self.destination = self.location.up_connection
yield self.env.timeout(self.location.travel_delay)
node_occupancy(nodes, loc, 5)
Теперь запустите симуляцию с маркером для текущего узла:
env.process(Occupier(env).travel(nodes[3], 3))
env.process(Occupier(env).travel(nodes[0], 0))
Посмотрите на результаты, и вы заметите, что события (запрос / выпуск) происходят в одно и то же время, и одновременное заполнение ресурсом времени всегда = 0 (т. Е. Время между этапами "3" и "4" для одного и того же объекта будет быть всегда 0):
5 3 1 [1, 0, 0, 1, 0, 0, 0, 0, 0, 0]
5 3 2 [1, 0, 0, 1, 1, 0, 0, 0, 0, 0]
5 0 1 [1, 0, 0, 1, 1, 0, 0, 0, 0, 0]
5 0 2 [1, 1, 0, 1, 1, 0, 0, 0, 0, 0]
5 3 3 [1, 1, 0, 1, 1, 0, 0, 0, 0, 0]
5 3 4 [1, 1, 0, 0, 1, 0, 0, 0, 0, 0]
5 0 3 [1, 1, 0, 0, 1, 0, 0, 0, 0, 0]
5 0 4 [0, 1, 0, 0, 1, 0, 0, 0, 0, 0]