The previously made decision has race conditions and does not work with map and async functions.
The correct way to handle Ctrl + C / SIGINT with multiprocessing.Pool :
- Before the
Pool process is created, make the process ignore SIGINT . Thus, the created child processes inherit the SIGINT handler. - Restore the original
SIGINT handler in the parent process after creating the Pool . - Use
map_async and apply_async instead of blocking map and apply . - Wait for the results with a timeout, because the default lock waits to ignore all signals. This is a Python bug https://bugs.python.org/issue8296 .
Combining this:
#!/bin/env python from __future__ import print_function import multiprocessing import os import signal import time def run_worker(delay): print("In a worker process", os.getpid()) time.sleep(delay) def main(): print("Initializng 2 workers") original_sigint_handler = signal.signal(signal.SIGINT, signal.SIG_IGN) pool = multiprocessing.Pool(2) signal.signal(signal.SIGINT, original_sigint_handler) try: print("Starting 2 jobs of 5 seconds each") res = pool.map_async(run_worker, [5, 5]) print("Waiting for results") res.get(60)
As Yakov Shklarov noted, there is a window of time between ignoring the signal and not naming it in the parent process, during which the signal can be lost. Using pthread_sigmask instead of temporarily blocking signal delivery in the parent process will not allow signal loss, however it is not available in Python-2.
Maxim Egorushkin Feb 01 '16 at 15:33 2016-02-01 15:33
source share