Someone pinged me recently – he was having a problem handling a keyboard interrupt when using multiprocessing.Pool.
Fundamentally, the problem comes with the fact that if a process gets an exception, it just throws the exception instead of returning or becoming .join()-able by the parent. You want to use pool.terminate() in the main function – but you also need to capture and handle the exception in the child so that when then exception is caught – the process can exit “gracefully”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | import multiprocessing import time def create(): try: time.sleep(10) except KeyboardInterrupt: return return 'hi mom' def main(): def cb(what): print what pool = multiprocessing.Pool(2) try: for i in range(2): pool.apply_async(create, args=(), callback=cb) pool.close() pool.join() except KeyboardInterrupt: print 'control-c presd butan' pool.terminate() if __name__ == "__main__": main() |
If the exception is thrown within the child, and it just raises – it becomes unmanageable by the parent. As you can see from this piece of code (from pool.py, python trunk) the Pool is attempting to join() the child – which is of course, unjoinable (sort of like me, when I was a teenager):
1 2 3 4 5 6 7 8 | @classmethod def _terminate_pool(cls, taskqueue, inqueue, outqueue, pool, task_handler, result_handler, cache): ... if pool and hasattr(pool[0], 'terminate'): debug('joining pool workers') for p in pool: p.join() |