Cactusman
Cactusman

Reputation: 345

Simpy 3: Resources.Resource.request()/.release() WITHOUT 'with...as:'

I'm trying to add SimPy simulation to a project I'm working on and I have some confusion about version 3's release/request.

I was able to implement resources using a 'with'-block without trouble but in my situation I want to request/release a resource without using a 'with'-block.

However, I cannot find an example of this using SimPy 3. I read the documentation/source regarding resources but still can't get it quite right. Could someone explain how to properly:

...
Request a Resource with the method: 'request()'
...
Release that Resource with the method: 'release()'
...

Thanks, and sorry for the bother.

PS: I'm intending to use Resources.resource

Upvotes: 3

Views: 2531

Answers (3)

Stefan Scherfke
Stefan Scherfke

Reputation: 3232

If you want to use a resource without a with block (and you know you won’t get interrupted), its just:

req = resource.request()
yield req
# do stuff
resource.release(req)

Upvotes: 6

dano
dano

Reputation: 94951

Using with on an object calls __enter__ when you enter the with block, and __exit__ when you leave. So when you do

res = resource.Resource()
with res.request() as req:
  # stuff

You're really calling __enter__ on a Request object, doing #stuff then calling __exit__:

class Request(base.Put):
    def __exit__(self, exc_type, value, traceback):
        super(Request, self).__exit__(exc_type, value, traceback)
        self.resource.release(self)

class Put(Event):  # base.Put
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        # If the request has been interrupted, remove it from the queue:
        if not self.triggered:
            self.resource.put_queue.remove(self)

So, the with block is equivalent to this:

res = resource.Resource(...)
req = res.request()
#stuff
if not req.triggered:
   res.put_queue.remove(req)
   res.release(req)

However, the with block is also making sure that the cleanup code is called no matter what exceptions are thrown during #stuff. You'll lose that with the above code.

Upvotes: 3

will
will

Reputation: 10650

It's all outlined in PEP343;

with EXPR as VAR:
        BLOCK

becomes:

mgr = (EXPR)
exit = type(mgr).__exit__  # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
    try:
        VAR = value  # Only if "as VAR" is present
        BLOCK
    except:
        # The exceptional case is handled here
        exc = False
        if not exit(mgr, *sys.exc_info()):
            raise
        # The exception is swallowed if exit() returns true
finally:
    # The normal and non-local-goto cases are handled here
    if exc:
        exit(mgr, None, None, None)

This is exactly how python uses with... as... blocks, but I'm presuming there's some reason you don't want to use these. If that's the case, then you just need the __enter__ and __exit__ functions. The way i think of it, is __enter__ sets everything up, and __exit__ does all the cleanup.

Upvotes: 0

Related Questions