1

Within Simpy, I have multiple resources that can do the same job, but they are different so I can't just increase the capacity. Picture a single queue in a shopping centre that leads to all tellers. Some are manned and some are self serve. I put a request for both (two separate requests), and then yield rq_manned OR rq_selfserve, satisfied if atleast one of the requests is granted.

The problem is, what if they both become available at the same time, I don't want to actually request them both. What to do?

Dan Bouche
  • 11
  • 1

2 Answers2

0

Something like this might work:

with rq_manned.request() as manned_req, rq_selfserve.request() as sserve.req:
   result = yield manned_req | sserve.req
   if manned_req in result:
      do_manned_register_stuff()
   else:
      do selfserved_register_stuff()
TomR
  • 76
  • 2
  • Hi Tom, thank you for your response. That might work, the risk that I see is that if it collects them both at the same time, it may not actually release the selfserved_register resource until completion of the do_manned_register_stuff, which could be a very long time. My understanding of using the 'with' statement is that the resource isn't released until you reach a part of the code that is "unindented". – Dan Bouche Apr 23 '20 at 06:59
  • Another method is to use Stores instead of Resources. You can set up the individual resources in the store with attributes that can both differ or be the same. So I can set up self_serve & manned registers, they can all have the attribute that they are able to checkout customers, but they can also have differing attributes (e.g. if available, manned is quicker as they pack your bags). I think you can also do a priority, in case both become available at the same time. https://simpy.readthedocs.io/en/latest/topical_guides/resources.html – Dan Bouche Apr 23 '20 at 07:08
  • Hi Dan, my requirement is similar to yours but with more dynamic content. I have many dynamic request objects and based on the task I have to yield a few out of many to do some stuff\task. Any idea of how to construct the yield statement on the fly and also to release the unused ones. – Rishi Sep 10 '20 at 05:13
0

I guess that the central issue is that SimPy doesn't see a User asking for any of several resources. It sees independent Requests on each one of the resources, without worrying about who made them.

Therefore, as you pointed out, SimPy's yield env.any_of() is not useful here, given that every single Request will go through the process of queueing, using and releasing its respective resource.

I was personally struggling with similar issues and ended up deciding to create a higher layer of abstraction on top of SimPy, which is now the Chronon project.

In Chronon, your request would be expressed as something like:

yield user.waits(
   [self_teller01, self_teller02, ..., manned_teller01, manned_teller02, ...],
   which='any'
)

by which the user waits for any of the resources in the list, withdrawing all the other requests when access is obtained to one of them.

This example of a bike sharing system demonstrates all the functionality you probably need.

amigo
  • 23
  • 3