8.13. Control del bucle

La mayoría de los scripts de asyncio nunca tocan el bucle de eventos directamente – asyncio.run() es suficiente. Esta página cubre la interfaz de Loop para los casos en que no lo es: instalar un manejador de excepciones, ejecutar el bucle con un ciclo de vida distinto al de run, o conservar el objeto del bucle para instrumentación.

8.13.1. Obtener el bucle

  • asyncio.get_event_loop() – devuelve el objeto Loop. Es seguro llamarlo desde dentro o fuera de una corrutina.

  • asyncio.new_event_loop() – en MicroPython, reinicia el estado del bucle existente en lugar de crear uno nuevo. Vale la pena repetir la nota: hay exactamente un bucle de eventos por programa.

No existe ninguna API para ejecutar el bucle distinta de los métodos de Loop y asyncio.run().

8.13.2. Ejecutar el bucle directamente

asyncio.run() es el punto de entrada adecuado para casi cualquier aplicación. Existen dos métodos de Loop para los casos en que no lo es.

  • run_until_complete() – dado un awaitable, ejecuta el bucle hasta que ese awaitable finaliza y luego devuelve su resultado. Equivalente a una única llamada a asyncio.run(), omitiendo el desmontaje del bucle.

  • run_forever() – ejecuta el bucle hasta que se llama a stop() desde dentro de una tarea. No hay ningún awaitable de nivel superior; se espera que la aplicación planifique todo lo que necesite mediante asyncio.create_task() antes de llamar a run_forever.

Los métodos complementarios son stop() (solicitar que el bucle se detenga después de que la tarea actual finalice) y close() (liberar los recursos del bucle).

8.13.3. Creación de tareas desde el bucle

  • create_task() – la misma operación que asyncio.create_task(). La función libre existe para que el código de la aplicación no necesite una referencia al bucle en el caso común; el método existe para la instrumentación que ya dispone de una.

8.13.4. Manejadores de excepciones

El bucle llama a un manejador cuando una tarea lanza una excepción que nada en la cadena de llamadas de la corrutina ha capturado – un caso típico es una tarea que la aplicación creó con asyncio.create_task() y nunca esperó. El manejador predeterminado imprime una traza a través de sys.stderr; la página de excepciones mostró cómo cambiarlo por algo personalizado.

  • set_exception_handler() – instala un manejador personalizado. El manejador es un invocable handler(loop, context) donde context es un dict con al menos 'message' y, normalmente, 'exception' y 'future'.

  • get_exception_handler() – devuelve el manejador instalado actualmente, o None si se está usando el predeterminado.

  • default_exception_handler() – el manejador integrado. Útil dentro de un manejador personalizado que quiere ejecutar también el comportamiento predeterminado (registrar en la memoria flash y imprimir una traza, por ejemplo).

  • call_exception_handler() – ejecuta el manejador instalado actualmente con un dict de contexto construido a mano. Lo usa principalmente el propio bucle; una aplicación rara vez lo necesita.