9

Suppose that I have a threading.Lock() object that I want to acquire in order to use a resource. Suppose I want to use a try ... except ... clause with the resource.

There are several ways of doing this.

Method 1

import threading
lock = threading.Lock()
try:
    with lock:
        do_stuff1()
        do_stuff2()
except:
    do_other_stuff()

If an error occurs during do_stuff1() or do_stuff2(), will the lock be released? Or is it better to use one of the following methods?

Method 2

with lock:
    try:
        do_stuff1()
        do_stuff2()
    except:
        do_other_stuff()

Method 3

lock.acquire():
try:
    do_stuff1()
    do_stuff2()
except:
    do_other_stuff()
finally:
    lock.release()

Which method is best for the lock to be released even if an error occurs?

Julien Spronck
  • 15,069
  • 4
  • 47
  • 55
  • [`try:..except:pass`](http://stackoverflow.com/q/21553327/1903116) is very bad. – thefourtheye Mar 31 '15 at 16:19
  • I personally prefer 1st method without `try..except` – thefourtheye Mar 31 '15 at 16:19
  • 4
    This is the *whole point* of `with`, the `__exit__` part of the context manager releases the lock whatever happens. If you want to catch errors in what you do with it, the `try` should be *inside* the `with` (Method 2). – jonrsharpe Mar 31 '15 at 16:19
  • @thefourtheye it's an example, I know that ... thanks though :-) – Julien Spronck Mar 31 '15 at 16:19
  • 1
    The first method releases the lock _before_ calling `do_other_stuff()` thus you reduce the time the lock is taken, reducing contention. Perhaps by a minimal factor, but still. – Maciej Gol Mar 31 '15 at 16:30
  • @jonrsharpe thanks ... feel free to post your comment as an answer. That's probably as good as it gets. – Julien Spronck Mar 31 '15 at 16:39

1 Answers1

9

The with "context manager" requires an __exit__ method, which in this case will ensure that, whatever happens, the lock is released.

If you want to handle exceptions that occur during whatever it is that you're doing with that lock, you should put the try inside the with block, i.e. Method 2 is the correct approach. In general, you should always aim to minimise the amount of code within the try block.

You should also be as specific as possible about what could go wrong; a bare except: is bad practice (see e.g. "the evils of except"). At the very least (even for a simple example!) you should use except Exception:.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437