Recibir Señales Unix¶
Las notificaciones de eventos del sistema Unix normalmente interrumpen una
aplicación, desencadenando su manejador. Cuando se usa con asyncio
,
devoluciones de llamada del manejador de señales están intercaladas con las
otras co-rutinas y devoluciones de llamada gestionadas por el bucle de eventos.
Esto resulta en menos funciones interrumpidas, y la necesidad resultante de
proporcionar guardas de seguridad para la limpieza de operaciones incompletas.
import asyncio
import functools
import os
import signal
def signal_handler(name):
print('signal_handler({!r})'.format(name))
Los manejadores de señal se registran utilizando add_signal_handler()
. El
primer argumento es la señal y el segundo es la devolución de llamada. Las
devoluciones de llamada se pasan sin argumentos, por lo que si se necesitan
argumentos una función puede ser envuelta con functools.partial()
.
event_loop = asyncio.get_event_loop()
event_loop.add_signal_handler(
signal.SIGHUP,
functools.partial(signal_handler, name='SIGHUP'),
)
event_loop.add_signal_handler(
signal.SIGUSR1,
functools.partial(signal_handler, name='SIGUSR1'),
)
event_loop.add_signal_handler(
signal.SIGINT,
functools.partial(signal_handler, name='SIGINT'),
)
Este programa de ejemplo utiliza una co-rutina para enviarse señales a través
de os.kill()
. Después de que se envía cada señal, la co-rutina cede el
control para permitir que el manejador se ejecute. En una aplicación normal,
habría más lugares donde el código de la aplicación cede al bucle de eventos y
no se necesitaría un rendimiento artificial como este.
async def send_signals():
pid = os.getpid()
print('starting send_signals for {}'.format(pid))
for name in ['SIGHUP', 'SIGHUP', 'SIGUSR1', 'SIGINT']:
print('sending {}'.format(name))
os.kill(pid, getattr(signal, name))
# Yield control to allow the signal handler to run,
# since the signal does not interrupt the program
# flow otherwise.
print('yielding control')
await asyncio.sleep(0.01)
return
El programa principal ejecuta send_signals()
hasta que haya enviado todas
las señales
try:
event_loop.run_until_complete(send_signals())
finally:
event_loop.close()
La salida muestra cómo se llaman los manejadors cuando send_signals()
cede
el control después de enviar una señal.
$ python3 asyncio_signal.py
starting send_signals for 21772
sending SIGHUP
yielding control
signal_handler('SIGHUP')
sending SIGHUP
yielding control
signal_handler('SIGHUP')
sending SIGUSR1
yielding control
signal_handler('SIGUSR1')
sending SIGINT
yielding control
signal_handler('SIGINT')
Ver también
signal
– Recibir notificación de eventos asíncronos del sistema.