1

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

Joshua
  • 197
  • 12
  • Are you expecting lines after `yield` to be executed right away? When `yield` is used, nothing after it will be executed, just like a `return`. Execution will resume on the line after the `yield` keyword was used, but only if you call `.next()` on the output of the first `yield`. – Random Davis Mar 22 '19 at 19:50
  • 1
    Not the next time it is called, but the next time `next` is called on its return value. – chepner Mar 22 '19 at 19:50
  • 1
    Possible duplicate of [What does the "yield" keyword do?](https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do) – pault Mar 22 '19 at 19:51
  • See [these](https://www.dabeaz.com/generators/) [tutorials](http://www.dabeaz.com/finalgenerator/) to get up to speed with generators, from the great [David Beazley](https://stackoverflow.com/users/288810/david-beazley). – Peter Wood Mar 22 '19 at 19:53
  • Sorry I probably need to clarify. I understand that the 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. – Joshua Mar 22 '19 at 19:54
  • @Joshua it returns a generator which needs to be consumed to move forward. – Peter Wood Mar 22 '19 at 19:55
  • @Random Davis I'm expecting the lines after yield to get executed if there is a free unit of resource when making the request(). If there are none, I expect a pause until another function frees up the resource. Am I understanding how this works correctly? – Joshua Mar 22 '19 at 19:57
  • @Joshua All examples i found from simpy use something like `with self.staff.request() as req: yield req;`, is the usage without `with` supported? Cancel that, guess it should work. Do you release the resource after using it? – syntonym Mar 22 '19 at 20:00
  • @syntonym According to the docs which I cannot seem to find right now, using "with" immediately releases the resource. However, I would like the request to be stored for release by a different instance (any customer can free up any unit of resource). See this page where it does not use with: https://simpy.readthedocs.io/en/3.0.6/topical_guides/resources.html – Joshua Mar 22 '19 at 20:05
  • @Joshua so the code after the request ist not even executed once? You could check by adding a `print` directly after the `yield req`. – syntonym Mar 22 '19 at 20:06
  • @syntonym Unfortunately so. I tried placing a print at the very start of the function as well to test it but it does not execute even once. – Joshua Mar 22 '19 at 20:07

1 Answers1

0

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.

syntonym
  • 7,134
  • 2
  • 32
  • 45
  • This actually solved the problem! I have a release function but I was intentionally keeping it overutilised to see if resources were getting blocked properly – Joshua Mar 22 '19 at 20:28