Volver a Python Intermedio
Programación Asíncrona con asyncio
La programación asíncrona te permite ejecutar tareas concurrentes sin hilos, ideal para operaciones de E/S como solicitudes HTTP y consultas a bases de datos.
Lo Básico
import asyncio
async def saludar(nombre, demora):
await asyncio.sleep(demora) # Espera no bloqueante
print(f"¡Hola, {nombre}!")
async def principal():
await saludar("Alice", 1)
await saludar("Bob", 0.5)
asyncio.run(principal())
# (Después de 1.5 segundos) ¡Hola, Alice! luego ¡Hola, Bob!
Ejecución Concurrente con gather
import asyncio
async def obtener_usuario(user_id):
await asyncio.sleep(0.5) # Simular llamada de red
return {"id": user_id, "nombre": f"Usuario_{user_id}"}
async def principal():
# Ejecutar las 3 de forma concurrente — tarda ~0.5s, no 1.5s
usuarios = await asyncio.gather(
obtener_usuario(1),
obtener_usuario(2),
obtener_usuario(3),
)
for usuario in usuarios:
print(usuario)
asyncio.run(principal())
async with (Gestores de Contexto)
import asyncio
import aiohttp # pip install aiohttp
async def obtener_json(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.json()
async def principal():
datos = await obtener_json("https://api.ejemplo.com/usuarios")
print(datos)
async for (Iteradores Asíncronos)
async def resultados_paginados():
for pagina in range(1, 4):
await asyncio.sleep(0.1) # Simular carga de página
yield [f"item_{pagina}_{i}" for i in range(3)]
async def principal():
async for items in resultados_paginados():
print(items)
Tareas y Cancelación
import asyncio
async def trabajador(nombre, duracion):
try:
print(f"{nombre} iniciado")
await asyncio.sleep(duracion)
print(f"{nombre} completado")
except asyncio.CancelledError:
print(f"¡{nombre} fue cancelado!")
raise
async def principal():
tarea = asyncio.create_task(trabajador("Tarea A", 10))
await asyncio.sleep(2)
tarea.cancel()
try:
await tarea
except asyncio.CancelledError:
pass
Semáforos (Limitar Concurrencia)
import asyncio
async def peticion_limitada(semaforo, url):
async with semaforo:
# Máximo 5 peticiones concurrentes
await asyncio.sleep(0.2) # Simular petición
return f"Datos de {url}"
async def principal():
semaforo = asyncio.Semaphore(5)
urls = [f"https://api.ejemplo.com/{i}" for i in range(20)]
resultados = await asyncio.gather(
*[peticion_limitada(semaforo, url) for url in urls]
)
Cuándo usar async: Para tareas vinculadas a E/S (HTTP, BD, archivos). Para tareas vinculadas a CPU, usa
multiprocessingen su lugar.