# Ejecutores

Código fuente: Lib/asyncio/runners.py

Esta sección muestra 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)

  Ejecutar el coroutine coro y retornar el resultado.

  Esta función ejecuta la co-rutina pasada, teniendo cuidado de manejar el bucle de eventos asyncio, terminando los generadores asíncronos y cerrando el pool de hilos.

  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 debug. `False` deshabilita el modo debug de manera explícita. `None` se usa para respetar la configuración global Modo depuración.

  Esta función siempre crea un nuevo bucle de eventos y lo cierra al final. Debería ser usado como el punto de entrada principal para programas asyncio e idealmente, llamado una sola vez.

  Ejemplo:

      async def main():
          await asyncio.sleep(1)
          print('hello')

      asyncio.run(main())

  Nuevo en la versión 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 debug.

## Administrador de contexto del ejecutor

class asyncio.Runner(*, debug=None, loop_factory=None)

  Un administrador de contexto que simplifica multiples llamadas asíncronas en el mismo contexto.

  A veces varias funciones asíncronas de alto nivel deberían ser llamadas en el mismo bucle de eventos y `contextvars.Context`.

  Si debug es `True`, el bucle de eventos se ejecutará en modo debug. `False` deshabilita el modo debug 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 de la loop_factory configurar el bucle creado como el bucle actual. Por defecto `asyncio.new_event_loop()` es usado y configura el nuevo bucle de eventos como el actual con `asyncio.set_event_loop()` si loop_factory es `None`.

  Básicamente, el ejemplo `asyncio.run()` puede ser re-escrito usando el ejecutor:

      async def main():
          await asyncio.sleep(1)
          print('hello')

      with asyncio.Runner() as runner:
          runner.run(main())

  Nuevo en la versión 3.11.

  run(coro, *, context=None)

    Ejecuta una co-rutina coro en el bucle embebido.

    Retorna el resultado de la co-rutina o lanza excepción de dicha co-rutina.

    Un argumento opcional del contexto 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 es `None`.

    Esta función no puede ser llamada cuando otro bucle de eventos asyncio está corriendo en el mismo hilo.

  close()

    Cierra el ejecutor.

    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 ejecutor.

  Nota

  `Runner` usa una estrategia de inicialización perezosa, su constructor no inicializa las estructuras de bajo nivel subyacentes.

  El bucle y el contexto embebidos son creados al entrar al cuerpo `with` o en la primera llamada a `run()` o a `get_loop()`.

## Manejando interrupciones de teclado

Nuevo en la versión 3.11.

Cuando la excepción `signal.SIGINT` es lanzada por ``Ctrl`-`C``, la excepción `KeyboardInterrupt` es lanzada en el hilo principal por defecto. Sin embargo, esto no siempre funciona con `asyncio` porque puede interrumpir llamadas internas a asyncio e impedir la salida del programa.

Para mitigar este problema, `asyncio` maneja `signal.SIGINT` de la siguiente forma:

1. `asyncio.Runner.run()` instala un administrador `signal.SIGINT` personalizado antes que cualquier código de usuario sea ejecutado y lo remueve a la salida de la función.

2. La `Runner` crea la tarea principal que será pasada a la co-rutina para su ejecución.

3. When `signal.SIGINT` is raised by ``Ctrl`-`C``, the custom signal handler cancels the main task by calling `asyncio.Task.cancel()` which raises `asyncio.CancelledError` inside the main task. This causes the Python stack to unwind, `try/except` and `try/finally` blocks can be used for resource cleanup. After the main task is cancelled, `asyncio.Runner.run()` raises `KeyboardInterrupt`.

4. 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 inmediatamente `KeyboardInterrupt` sin cancelar la tarea principal.