6.1 Obteniendo el bucle de eventos
El Bucle de Eventos (Event Loop)
es un componente central en la programación asíncrona usando el módulo asyncio en Python. Gestiona la ejecución de tareas asíncronas, el manejo de eventos y la ejecución de operaciones de entrada/salida. El bucle de eventos permite que múltiples tareas se ejecuten al mismo tiempo sin bloquear el hilo principal de ejecución.
Creación y obtención del bucle de eventos
-
asyncio.get_event_loop()
: Devuelve el bucle de eventos actual o crea uno nuevo si no hay uno. -
asyncio.new_event_loop()
: Crea un nuevo bucle de eventos. -
asyncio.set_event_loop(loop)
: Establece el bucle de eventos indicado como el actual.
Ejemplo:
asyncio tiene un bucle de eventos actual que contiene todas las tareas ejecutándose. Puedes obtener el bucle de eventos actual o crear uno nuevo y establecerlo como el actual. Esto es lo que pasa en el ejemplo de abajo.
import asyncio
loop = asyncio.get_event_loop()
print(loop) # Bucle de eventos actual
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)
print(asyncio.get_event_loop()) # Nuevo bucle de eventos establecido
Vale la pena notar que el método get_event_loop()
devuelve el bucle de eventos activo actual. La creación de un nuevo bucle de eventos y su establecimiento debe hacerse con precaución para evitar conflictos en aplicaciones asíncronas.
Ejecutando el bucle de eventos
-
run_forever()
: Ejecuta el bucle de eventos y continúa su ejecución hasta que se llama astop()
. -
run_until_complete(future)
: Ejecuta el bucle de eventos y lo detiene al finalizar la coroutine dada o el objeto futurible.
Ejemplo:
El bucle de eventos se puede ejecutar en dos modos: trabajar infinitamente — algo como un while True
, o hasta que se complete una tarea específica.
import asyncio
async def hello():
print("Hello")
await asyncio.sleep(1)
print("World")
loop = asyncio.get_event_loop()
loop.run_until_complete(hello())
loop.close()
Si iniciaste el Event Loop
en modo run_forever()
, estará dando vueltas internamente infinitamente. El método run_forever()
solo finalizará si alguna tarea asíncrona invoca el método stop()
en nuestro EventLoop
.
Detener el bucle de eventos
stop()
: Detiene el bucle de eventos.-
is_running()
: DevuelveTrue
si el bucle de eventos está en ejecución.
Ejemplo:
Si el bucle se ejecuta en modo infinito, está constantemente recibiendo tareas y ejecutándolas, no se detendrá por sí solo. Alguien debe obtener el objeto de nuestro bucle actual y llamar al método stop()
en él. Para saber si el bucle infinito está activo o no, hay que llamar al método is_running()
.
import asyncio
loop = asyncio.get_event_loop()
loop.stop()
print(loop.is_running()) # False
6.2 Métodos importantes del bucle de eventos
Método call_soon(callback, *args)
Planifica la llamada de la función callback
con argumentos *args
lo más pronto posible.
import asyncio
def my_callback():
print("Callback ejecutado")
loop = asyncio.get_event_loop()
loop.call_soon(my_callback)
loop.run_forever()
Coloca la función callback
al inicio de la lista de tareas para que comience a ejecutarse lo más pronto posible. Puedes pasar funciones no asíncronas a este método. Este método es útil cuando necesitas realizar una tarea con el menor retraso posible, especialmente cuando se requiere una respuesta inmediata en una aplicación asíncrona.
Método call_later(delay, callback, *args)
Planifica la llamada de la función callback
con argumentos *args
después de delay
segundos.
import asyncio
def my_callback():
print("Callback ejecutado tras retraso")
loop = asyncio.get_event_loop()
loop.call_later(2, my_callback)
loop.run_forever()
Este método permite realizar una llamada diferida a una función: el primer argumento es el retraso en segundos (puede ser fraccionario), el siguiente es una referencia a la función y sus parámetros. Puedes pasar funciones no asíncronas a este método. Este método se puede usar para gestionar la ejecución de tareas con diferentes niveles de urgencia, lo que es útil al diseñar sistemas asíncronos complejos.
Método call_at(when, callback, *args)
Planifica la llamada de la función callback
con argumentos *args
en el momento when
.
import asyncio
import time
def my_callback():
print("Callback ejecutado en tiempo específico")
loop = asyncio.get_event_loop()
when = loop.time() + 2 # Dentro de 2 segundos desde el tiempo actual del bucle de eventos
loop.call_at(when, my_callback)
loop.run_forever()
Si quieres ejecutar una tarea no en 5 segundos, sino, por ejemplo, a las 15:00 o las 24:00, te será más conveniente usar la función call_at()
, que funciona igual que la función call_soon()
, pero como primer parámetro recibe no la duración de la pausa, sino el tiempo en el que se debe llamar a la función dada. Puedes pasar funciones no asíncronas a este método.
Ventajas y características
Ejecución asíncrona: El bucle de eventos permite ejecutar muchas tareas en paralelo sin bloquear el hilo principal de ejecución.
Gestión eficiente de recursos: Las operaciones de entrada/salida asíncronas se ejecutan sin bloqueo, lo que hace que los programas sean más eficientes.
Flexibilidad y escalabilidad: El bucle de eventos soporta muchos métodos para planificar tareas y manejar eventos, lo que permite crear aplicaciones asíncronas complejas y escalables.
6.3 Interacción con tareas y objetos futuros
El bucle de eventos gestiona la ejecución de tareas (Tasks) y objetos futuros (Futures). Monitorea su estado y asegura su ejecución a medida que están listos.
Ejemplo:
import asyncio
async def main():
await asyncio.sleep(1)
print("Tarea completada")
loop = asyncio.get_event_loop()
task = loop.create_task(main())
loop.run_until_complete(task)
En este ejemplo se muestra cómo el bucle de eventos gestiona la ejecución de una tarea creada con el método create_task
. Los métodos call_soon()
, call_later()
y call_at()
se pueden usar para gestionar la ejecución de tareas con diferentes niveles de urgencia, lo que es útil al diseñar sistemas asíncronos complejos.
GO TO FULL VERSION