How to terminate loop.run_in_executor with ProcessPoolExecutor gracefully?
You can use the initializer
parameter of ProcessPoolExecutor
to install a handler for SIGINT
in each process.
Update:On Unix, when the process is created, it becomes a member of the process group of its parent. If you are generating the SIGINT
with Ctrl+C
, then the signal is being sent to the entire process group.
import asyncioimport concurrent.futuresimport osimport signalimport sysfrom time import sleepdef handler(signum, frame): print('SIGINT for PID=', os.getpid()) sys.exit(0)def init(): signal.signal(signal.SIGINT, handler)def blocking_task(): sleep(15)async def main(): exe = concurrent.futures.ProcessPoolExecutor(max_workers=5, initializer=init) loop = asyncio.get_event_loop() tasks = [loop.run_in_executor(exe, blocking_task) for i in range(2)] await asyncio.gather(*tasks)if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: print('ctrl + c')
Ctrl-C
shortly after start:
^CSIGINT for PID= 59942SIGINT for PID= 59943SIGINT for PID= 59941SIGINT for PID= 59945SIGINT for PID= 59944ctrl + c