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 multiprocessing en su lugar.