Simpy: одновременно освободить ресурс при выделении нового ресурса - PullRequest
0 голосов
/ 18 октября 2018

Я упростил версию проблемы, которую я пытаюсь смоделировать, где я использую 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 Ответ

0 голосов
/ 23 октября 2018

На самом деле ваша модель работает правильно.

Попробуйте добавить к функции 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]
...