Event loop de asyncio: creación manual y debugging avanzado

Clase 14 de 17Curso de Python Profesional: Arquitectura de Proyectos, Entornos y PyPI

Resumen

Domina el event loop de asyncio con ejemplos claros y prácticos. Aquí verás cómo funciona, cuándo conviene usar asyncio.run y cuándo gestionar el loop manualmente, además de activar debug para entender qué sucede bajo el capó sin bloquear tu programa.

¿Qué es el event loop en asyncio y cómo coordina corutinas?

El event loop es el corazón de asyncio: coordina corutinas y decide cuándo pausarlas y reanudarlas. Piensa en un director de orquesta que no ejecuta, pero hace que todo suene a tiempo.

  • Revisa tareas listas. Busca corutinas listas para ejecutarse.
  • Ejecuta hasta la await. Corre cada tarea hasta encontrar un await.
  • Pausa y registra. Guarda el estado y anota qué está esperando.
  • Repite el ciclo. Permite progreso continuo de múltiples operaciones de IO sin bloquear.

¿Qué pasos clave siguen las tareas en el loop?

  • Se seleccionan tareas pendientes y se programan de forma no bloqueante.
  • Cada tarea avanza hasta su siguiente punto de espera con await.
  • El loop retoma tareas cuando su condición de espera se cumple.

¿Cuándo usar asyncio.run y cuándo gestión manual del loop?

En la mayoría de casos, usa asyncio.run: es más simple y seguro. Evita sobrecarga y maneja automáticamente la creación y cierre del loop.

Usa gestión manual del loop cuando:

  • Necesitas control fino del ciclo de vida del loop.
  • Integras asyncio con otros frameworks que ya manejan bucles de eventos.
  • Requieres debugging avanzado: activar debug y observar el comportamiento interno de asyncio.

¿Cómo crear y depurar un event loop manual en Python?

Puedes crear tu propio loop para tener acceso directo a su configuración. El flujo es: crear el loop, registrarlo en asyncio, ejecutar hasta completar la tarea y cerrarlo al final para liberar recursos.

import asyncio

async def main():
    # tu lógica asíncrona aquí
    return "ok"

# crear y registrar el loop
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)

try:
    # opcional: activar debug del loop
    loop.set_debug(True)

    # ejecutar hasta que la tarea termine
    loop.run_until_complete(main())
finally:
    # importante: cerrar el loop para liberar recursos
    loop.close()
  • new_event_loop. Crea una instancia de loop y la guarda en una variable, por ejemplo, my_loop.
  • set_event_loop. Indica a asyncio cuál loop debe usar.
  • run_until_complete. Ejecuta la tarea hasta completarse.
  • close. Cierra el loop en un bloque finally para no dejar recursos abiertos.

¿Cómo activar debug y ver logs de asyncio?

  • Usa loop.set_debug(True) para habilitar debug en el loop.
  • Ajusta tu configuración de logs a nivel debug para ver mensajes de asyncio, como el “selector” que está usando.
  • Ejecuta tu script y observa el logging de asyncio para entender qué tareas se seleccionan y cuándo avanzan.

Consejos prácticos:

  • En proyectos comunes, asyncio.run es suficiente y recomendable.
  • El control manual del loop es útil para escenarios específicos de integración y debug profundo.
  • Mantén la limpieza de recursos: siempre cierra el loop.

¿Te animas a practicar? Integra una librería para consultas a APIs de manera asíncrona y pruébala con gestión manual del loop o con asyncio.run. Comparte dudas y avances en comentarios.