La programación asíncrona apareció en el lenguaje Python a partir de la versión 3.5 con la introducción de las palabras clave async y await. Inicialmente, se utilizaban bibliotecas como asyncio y generadores basados en corutinas para tareas asíncronas, lo que era difícil de entender y mantener. Con la llegada de la sintaxis async/await, el código asíncrono se volvió más explícito y legible, acercándose al estilo sincrónico habitual.
Antes de la llegada de async/await, la asincronía se implementaba a través de callbacks y generadores (por ejemplo, utilizando la biblioteca tornado o las antiguas API de asyncio). Tal código era complicado de depurar y mantener.
El principal problema al manejar una gran cantidad de operaciones I/O simultáneas (solicitudes de red, entrada/salida de archivos) en código sincrónico es el bloqueo del hilo principal. Esto conduce a una disminución del rendimiento y a la imposibilidad de utilizar los recursos de manera efectiva.
La programación asíncrona mediante async/await permite realizar múltiples operaciones de entrada/salida en paralelo dentro de un solo hilo, evitando bloqueos. Además, la sintaxis es similar a las funciones normales, lo que facilita la legibilidad y la depuración.
import asyncio async def fetch_data(delay): print(f"Comenzando a obtener datos después de {delay}s de retraso") await asyncio.sleep(delay) print(f"Datos obtenidos después de {delay}s de retraso") return delay async def main(): resultados = await asyncio.gather( fetch_data(1), fetch_data(2), fetch_data(3) ) print("Resultados:", resultados) asyncio.run(main())
¿Puede una función definida con async def ser invocada como una función normal?
No. Llamar a tal función devuelve un objeto de corutina, que no se ejecuta hasta que se pasa al event loop (por ejemplo, mediante await o asyncio.run()).
def foo(): return 42 async def bar(): return 42 print(foo()) # 42 print(bar()) # <coroutine object bar at ...>
¿Se puede usar await fuera de una función asíncrona?
No. La palabra clave await debe usarse solo dentro de funciones declaradas con async def. Intentar poner await fuera de tal función causará SyntaxError.
# ¡Error! await asyncio.sleep(1) # SyntaxError: 'await' fuera de una función asíncrona
¿Funciona la asincronía para operaciones no relacionadas con I/O (por ejemplo, cálculos)?
No. La asincronía es efectiva solo para operaciones de entrada/salida. Para tareas computacionales, se necesita multiprocessing o threading, de lo contrario, se bloqueará el event loop.
Ventajas:
Desventajas:
Caso negativo: Desarrolladores novatos intentaron acelerar la aplicación usando async/await, pero hacían cálculos de forma asíncrona en lugar de solicitudes de red. La aplicación no se aceleró. Ventajas: se familiarizaron con la sintaxis. Desventajas: no hubo ganancias, el código se complicó.
Caso positivo: Procesaron asíncronamente miles de solicitudes a una API. El servidor pudo atender a más clientes sin aumentar los recursos. Ventajas: el rendimiento aumentó significativamente, la arquitectura se volvió más simple. Desventajas: aumentó la barrera de entrada para los novatos.