Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to gracefully end asyncio program with CTRL-C when using loop run_in_executor

The following code requires 3 presses of CTRL-C to end, how can I make it end with one only? (So it works nicely in Docker)

import asyncio
import time


def sleep_blocking():
    print("Sleep blocking")
    time.sleep(1000)


async def main():
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, sleep_blocking)


try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("Nicely shutting down ...")

I've read many asyncio related questions and answers but can't figure this one out yet. The 1st CTRL-C does nothing, the 2nd prints "Nicely shutting down ..." and then hangs. The 3rd CTRL-C prints an ugly error.

I'm on Python 3.9.10 and Linux.

(edit: updated code per comment @mkrieger1)

like image 281
Otto Avatar asked Sep 18 '25 02:09

Otto


1 Answers

From here we know that it's effectively impossible to kill a task running in a thread executor. If I replace the default thread executor with a ProcessPoolExecutor, I get the behavior you're looking for. Here's the code:

import concurrent.futures
import asyncio
import time


def sleep_blocking():
    print("Sleep blocking")
    time.sleep(1000)


async def main():
    loop = asyncio.get_event_loop()
    x = concurrent.futures.ProcessPoolExecutor()
    await loop.run_in_executor(x, sleep_blocking)


try:
    asyncio.run(main())
except KeyboardInterrupt:
    print("Nicely shutting down ...")

And the result is:

$ python asynctest.py
Sleep blocking
^CNicely shutting down ...
like image 127
larsks Avatar answered Sep 19 '25 17:09

larsks