My understanding is that finally clauses must *always* be executed if the try has been entered.
import random
from multiprocessing import Pool
from time import sleep
def Process(x):
try:
print x
sleep(random.random())
raise Exception('Exception: ' + x)
finally:
print 'Finally: ' + x
Pool(3).map(Process, ['1','2','3'])
Expected output is that for each of x which is printed on its own by line 8, there must be an occurrence of ‘Finally x’.
Example output:
$ python bug.py
1
2
3
Finally: 2
Traceback (most recent call last):
File "bug.py", line 14, in <module>
Pool(3).map(Process, ['1','2','3'])
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 225, in map
return self.map_async(func, iterable, chunksize).get()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/pool.py", line 522, in get
raise self._value
Exception: Exception: 2
It seems that an exception terminating one process terminates the parent and sibling processes, even though there is further work required to be done in other processes.
Why am I wrong? Why is this correct? If this is correct, how should one safely clean up resources in multiprocess Python?
Short answer:
SIGTERMtrumpsfinally.Long answer: Turn on logging with
mp.log_to_stderr():The logging output includes:
Which corresponds to this code in
multiprocessing.pool._terminate_pool:Each
pinpoolis amultiprocessing.Process, and callingterminate(at least on non-Windows machines) calls SIGTERM:from
multiprocessing/forking.py:So it comes down to what happens when a Python process in a
trysuite is sent aSIGTERM.Consider the following example (test.py):
If you run it, then send it a
SIGTERM, then the process ends immediately, without entering thefinallysuite, as evidenced by no output, and no delay.In one terminal:
In second terminal:
Result in first terminal:
Compare that with what happens when the process is sent a
SIGINT(C-c):In second terminal:
Result in first terminal:
Conclusion:
SIGTERMtrumpsfinally.