Closed
Description
Test program based on a SO question; press Ctrl-C after "coro stop" and before "thread stop":
import asyncio
import time
async def main():
print("coro start")
loop = asyncio.get_running_loop()
loop.run_in_executor(None, blocking)
await asyncio.sleep(1.0)
print("coro stop")
def blocking():
print("thread start")
time.sleep(3.0)
print("thread stop")
try:
asyncio.run(main())
except KeyboardInterrupt:
print("interrupted!")
The output is as expected:
coro start
thread start
coro stop
^Cinterrupted!
thread stop
but a stack trace is printed to stderr:
exception calling callback for <Future at 0x7fb3e38bc0a0 state=finished returned NoneType>
Traceback (most recent call last):
File "/usr/lib64/python3.10/concurrent/futures/_base.py", line 342, in _invoke_callbacks
callback(self)
File "/usr/lib64/python3.10/asyncio/futures.py", line 399, in _call_set_state
dest_loop.call_soon_threadsafe(_set_state, destination, source)
File "/usr/lib64/python3.10/asyncio/base_events.py", line 795, in call_soon_threadsafe
self._check_closed()
File "/usr/lib64/python3.10/asyncio/base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Exception in thread Thread-1 (_do_shutdown):
Traceback (most recent call last):
File "/usr/lib64/python3.10/asyncio/base_events.py", line 576, in _do_shutdown
self.call_soon_threadsafe(future.set_result, None)
File "/usr/lib64/python3.10/asyncio/base_events.py", line 795, in call_soon_threadsafe
self._check_closed()
File "/usr/lib64/python3.10/asyncio/base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib64/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/usr/lib64/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/usr/lib64/python3.10/asyncio/base_events.py", line 578, in _do_shutdown
self.call_soon_threadsafe(future.set_exception, ex)
File "/usr/lib64/python3.10/asyncio/base_events.py", line 795, in call_soon_threadsafe
self._check_closed()
File "/usr/lib64/python3.10/asyncio/base_events.py", line 515, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
The interrupt occurs in asyncio.run
at line 49 in the file asyncio/runners.py
39 loop = events.new_event_loop()
40 try:
41 events.set_event_loop(loop)
42 if debug is not None:
43 loop.set_debug(debug)
44 return loop.run_until_complete(main)
45 finally:
46 try:
47 _cancel_all_tasks(loop)
48 loop.run_until_complete(loop.shutdown_asyncgens())
49 loop.run_until_complete(loop.shutdown_default_executor())
50 finally:
51 events.set_event_loop(None)
52 loop.close()
The control returns to the main program (except KeyboardInterrupt
), but the cleanup waits
until the spawned thread terminates and at that time the event loop is closed and the RuntimeError
occurs.
In my opinion, no RuntimeError
should happen. Given that the entire user's program is guarded by
try-except
which successfully catches the KeyboardInterrupt
, there is very little a programmer
can do to avoid this situation maybe except suppressing the output by redirecting the stderr to /dev/null.
Your environment
Python 3.10
Metadata
Metadata
Assignees
Labels
only security fixesonly security fixesonly security fixesonly security fixesonly security fixesonly security fixesAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Projects
Status
Done