Runners¶
Código fuente: Lib/asyncio/runners.py
Esta sección describe las primitivas asyncio de alto nivel para ejecutar código asyncio.
Están construidos sobre un event loop con el objetivo de simplificar el uso de código async para escenarios comunes de alta difusión.
Ejecutando un programa asyncio¶
- asyncio.run(coro, *, debug=None, loop_factory=None)¶
Ejecutar el coroutine coro y retornar el resultado.
Esta función ejecuta la co-rutina pasada, encargándose de gestionar el bucle de eventos asyncio, finalizando los generadores asíncronos, y cerrando el ejecutor.
Esta función no puede ser llamada cuando otro bucle de eventos asyncio está corriendo en el mismo hilo.
Si debug es
True
, el bucle de eventos se ejecutará en modo depuración.False
deshabilita el modo depuración de manera explícita.None
se usa para respetar la configuración global Modo depuración.Si loop_factory no es
None
, se utiliza para crear un nuevo bucle de eventos; en caso contrario se utilizaasyncio.new_event_loop()
. El bucle se cierra al final. Esta función debería usarse como punto de entrada principal para los programas asyncio, e idealmente sólo debería llamarse una vez. Se recomienda usar loop_factory para configurar el bucle de eventos en lugar de políticas.Al ejecutor se le da un tiempo de espera de 5 minutos para apagarse. Si el ejecutor no ha finalizado en ese tiempo, se emite una advertencia y se cierra el ejecutor.
Ejemplo:
async def main(): await asyncio.sleep(1) print('hello') asyncio.run(main())
Added in version 3.7.
Distinto en la versión 3.9: Actualizado para usar
loop.shutdown_default_executor()
.Distinto en la versión 3.10: debug es
None
por defecto para respetar la configuración global del modo depuración.Distinto en la versión 3.12: Añadido el parámetro loop_factory.
Gestor de contexto del runner¶
- class asyncio.Runner(*, debug=None, loop_factory=None)¶
Un gestor de contexto que simplifica múltiples llamadas a funciones asíncronas en el mismo contexto.
A veces varias funciones asíncronas de alto nivel deben ser llamadas en el mismo event loop y
contextvars.Context
.Si debug es
True
, el bucle de eventos se ejecutará en modo depuración.False
deshabilita el modo depuración de manera explícita.None
se usa para respetar la configuración global Modo depuración.loop_factory puede ser usado para redefinir la creación de bucles. Es responsabilidad del loop_factory establecer el bucle creado como el actual. Por defecto
asyncio.new_event_loop()
es usado y configura el nuevo bucle de eventos como el actual conasyncio.set_event_loop()
si loop_factory esNone
.Basically,
asyncio.run()
example can be rewritten with the runner usage:async def main(): await asyncio.sleep(1) print('hello') with asyncio.Runner() as runner: runner.run(main())
Added in version 3.11.
- run(coro, *, context=None)¶
Ejecuta una co-rutina coro en el bucle incrustado.
Retorna el resultado de la co-rutina o lanza excepción de dicha co-rutina.
Un argumento opcional del context que consiste en una palabra clave permite especificar un
contextvars.Context
personalizado donde correr la coro . El contexto por defecto del ejecutor es usado si el modo debug esNone
.Esta función no puede ser llamada cuando otro bucle de eventos asyncio está corriendo en el mismo hilo.
- close()¶
Cierra el runner.
Termina los generadores asíncronos, apaga el ejecutor por defecto, cierra el bucle de eventos y libera el
contextvars.Context
embebido.
- get_loop()¶
Retorna el bucle de eventos asociado a la instancia del runner.
Nota
Runner
usa una estrategia de inicialización perezosa, su constructor no inicializa las estructuras de bajo nivel subyacentes.El loop y el context embebidos son creados al entrar al cuerpo
with
o en la primera llamada arun()
o aget_loop()
.
Manejando interrupciones de teclado¶
Added in version 3.11.
Cuando signal.SIGINT
es lanzada por Ctrl-C, la excepción KeyboardInterrupt
es lanzada en el hilo principal por defecto. Sin embargo, esto no funciona con asyncio
porque puede interrumpir las funciones internas a asyncio e impedir la salida del programa.
Para mitigar este problema, asyncio
maneja signal.SIGINT
de la siguiente forma:
asyncio.Runner.run()
instala un administradorsignal.SIGINT
personalizado antes que cualquier código de usuario sea ejecutado y lo remueve a la salida de la función.La
Runner
crea la tarea principal que será pasada a la co-rutina para su ejecución.Cuando
signal.SIGINT
es lanzada por Ctrl-C, el administrador de señales personalizado cancela la tarea principal llamando aasyncio.Task.cancel()
que lanzaasyncio.CancelledError
dentro de la tarea principal. Esto hace que la pila de Python se desenrolle, los bloquestry/except
ytry/finally
se pueden utilizar para la limpieza de recursos. Luego que la tarea principal es cancelada,asyncio.Runner.run()
lanzaKeyboardInterrupt
.Un usuario podría escribir un bucle cerrado que no puede ser interrumpido por
asyncio.Task.cancel()
, en cuyo caso la segunda llamada a Ctrl-C lanza inmediatamenteKeyboardInterrupt
sin cancelar la tarea principal.