Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I catch SIGINT when asyncio event loop is running?

Using Python 3.4.1 on Windows, I've found that while executing an asyncio event loop, my program can't be interrupted (i.e. by pressing Ctrl+C in the terminal). More to the point, the SIGINT signal is ignored. Conversely, I've determined that SIGINT is handled when not in an event loop.

Why is it that SIGINT is ignored when executing an asyncio event loop?

The below program should demonstrate the problem - run it in the terminal and try to stop it by pressing Ctrl+C, it should keep running:

import asyncio
import signal


# Never gets called after entering event loop
def handler(*args):
    print('Signaled')


signal.signal(signal.SIGINT, handler)

print('Event loop starting')
loop = asyncio.SelectorEventLoop()
asyncio.set_event_loop(loop)
loop.run_forever()
print('Event loop ended')

See discussion on official (Tulip) mailing list.

like image 304
aknuds1 Avatar asked Jul 16 '14 07:07

aknuds1


People also ask

How does the Asyncio event loop work?

The event loop is the core of every asyncio application. Event loops run asynchronous tasks and callbacks, perform network IO operations, and run subprocesses. Application developers should typically use the high-level asyncio functions, such as asyncio.

How many times should Asyncio run () be called?

How many times should Asyncio run () be called? It should be used as a main entry point for asyncio programs, and should ideally only be called once. New in version 3.7.

How do I close Asyncio event loop?

stop() – the stop function stops a running loop. is_running() – this function checks if the event loop is currently running or not. is_closed() – this function checks if the event loop is closed or not. close() – the close function closes the event loop.

How do I start Asyncio event loop?

The alternative way of starting up your event loop is to call the run_forever() method which will subsequently start your asyncio based event loop and have it run indefinitely until the program comes to an end or the stop() method is called.


1 Answers

I've found a workaround, which is to schedule a periodic callback. While this running, SIGINT is apparently processed:

import asyncio


def wakeup():
    # Call again
    loop.call_later(0.1, wakeup)


print('Event loop starting')
loop = asyncio.SelectorEventLoop()
# Register periodic callback
loop.call_later(0.1, wakeup)
asyncio.set_event_loop(loop)
loop.run_forever()
print('Event loop ended')

Not sure why this is necessary, but it indicates that signals are blocked while the event loop waits for events ("polls").

The matter has been discussed on the official (Tulip) mailing list, my workaround is apparently the way to go as of now.

Update

A fix has supposedly made its way into Python 3.5, so hopefully my workaround will be made obsolete by that Python version.

like image 78
aknuds1 Avatar answered Oct 18 '22 21:10

aknuds1