Search code examples
pythonyieldsimpy

Requesting a Simpy resource never succeeds


I'm currently trying to model a service counter with SimPy but I'm running into difficulties with using yield to hold the resources. Under the Counter.arrive() function, if the line "yield req" exists, the entire function skips execution (at least I think that's what happens since I don't get any of the print output). However, if I comment out that line, the code executes like nothing happens. This is a problem because without the yield the code is not blocked until the request is approved and the entire simulation fails because everyone gets to use the resource.

Code snippet as follows:

import simpy
class Counter:
    def __init__(self, env, name, staff):
        self.env = env
        self.staff = simpy.Resource(env, staff)
        self.name = name
        self.dreq = []
    def arrive(self, name):
        ...
        req = self.staff.request()
        yield req
        output = "Req: %s\n" % req
        self.dreq.append(req)
        ...
        print(output)
...
def customer(env, counter, name):
        print("Customer %s arrived at %s" %(name,env.now))
        counter.arrive(name)
        yield env.timeout(5)
        print("Customer %s left at %s" %(name,env.now))
...
env = simpy.Environment()
counter = Counter(env, "A", 1)
def setup(env, counter, MAX_CUST):
    for i in range(MAX_CUST):
        env.process(customer(env,counter, 1))
        yield env.timeout(1)
env.process(setup(env,counter,5))
env.run(until=100)

Edit: I understand that using yield should pause the function until the request gets approved but the very first request does not go through as well which does not make sense as there is 1 unit of the resource available at the start.

Docs for convenience: https://simpy.readthedocs.io/en/3.0.6/topical_guides/resources.html


Solution

  • Requests (and timeouts and everything which you need to yield) gets processed by simpy, so it needs to arrive at simpy to get processed. You tell simpy to process customer with env.process:

        env.process(customer(env,counter, 1))
    

    In customer you call counter.arrive(name). Because arrive is a generator (because of yield) it does nothing until something calls next on it. Simpy needs to know of it to process it properly. You should be able to do this by:

    env.process(counter.arrive(name))
    

    which should fix your problem.

    Note that also in this code you never release the ressource, so only one customer can actually arrive.