FastAPI: Asincronía

Descubre cómo usar la programación asíncrona en FastAPI para mejorar el rendimiento y gestionar múltiples tareas concurrentes en aplicaciones web.

Aprende FastAPI GRATIS y certifícate

Asincronía en FastAPI

La programación asíncrona representa un paradigma fundamental en el desarrollo web moderno, especialmente relevante cuando trabajamos con FastAPI. A diferencia de la programación tradicional síncrona, donde cada operación debe completarse antes de continuar con la siguiente, la asincronía permite que nuestras aplicaciones manejen múltiples tareas de forma concurrente.

¿Qué es la programación asíncrona?

En el contexto de aplicaciones web, la asincronía resulta especialmente valiosa cuando realizamos operaciones que requieren tiempo de espera, como consultas a bases de datos, llamadas a APIs externas o lectura de archivos. En lugar de bloquear toda la aplicación mientras esperamos una respuesta, el código asíncrono permite que otros procesos continúen ejecutándose.

Imagina un restaurante donde el camarero toma un pedido y se queda esperando junto a la cocina hasta que esté listo, sin atender a otros clientes. Esto sería el equivalente a la programación síncrona. En cambio, la programación asíncrona sería como un camarero que toma múltiples pedidos, los envía a la cocina y continúa atendiendo otros clientes mientras espera que los platos estén listos.

Conceptos fundamentales en Python

Python implementa la asincronía mediante las palabras clave async y await. Una función definida con async def se convierte en una función asíncrona o corrutina, que puede pausar su ejecución y ceder el control a otras tareas.

import asyncio

async def operacion_lenta():
    print("Iniciando operación...")
    await asyncio.sleep(2)  # Simula una operación que tarda 2 segundos
    print("Operación completada")
    return "Resultado"

La palabra clave await indica que en ese punto la función puede pausarse y permitir que otras tareas se ejecuten. Solo puede utilizarse dentro de funciones marcadas con async.

Asincronía en FastAPI

FastAPI está diseñado desde sus cimientos para aprovechar las ventajas de la programación asíncrona. Cuando definimos endpoints con async def, FastAPI puede manejar múltiples peticiones simultáneamente de forma eficiente.

from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get("/rapido")
async def endpoint_rapido():
    return {"mensaje": "Respuesta inmediata"}

@app.get("/lento")
async def endpoint_lento():
    await asyncio.sleep(3)  # Simula una operación que tarda 3 segundos
    return {"mensaje": "Operación completada después de 3 segundos"}

En este ejemplo, si múltiples usuarios acceden al endpoint /lento simultáneamente, FastAPI no bloqueará las peticiones. Cada una se procesará de forma concurrente, mejorando significativamente el rendimiento de la aplicación.

Cuándo usar funciones asíncronas

No todas las operaciones requieren asincronía. Las funciones asíncronas son más beneficiosas cuando realizamos operaciones de entrada/salida (I/O) que implican espera:

  • Consultas a bases de datos que pueden tardar varios milisegundos
  • Llamadas a APIs externas con tiempos de respuesta variables
  • Lectura de archivos grandes desde el disco
  • Operaciones de red como descargas o uploads
@app.get("/usuarios/{user_id}")
async def obtener_usuario(user_id: int):
    # Simula una consulta a base de datos
    await asyncio.sleep(0.1)  # 100ms de latencia típica de BD
    return {"id": user_id, "nombre": "Usuario Ejemplo"}

Diferencias entre sync y async

FastAPI permite definir endpoints tanto síncronos como asíncronos, y cada uno tiene su lugar apropiado:

Endpoints síncronos - para operaciones rápidas y cálculos:

@app.get("/calcular")
def calcular_factorial(n: int):
    resultado = 1
    for i in range(1, n + 1):
        resultado *= i
    return {"factorial": resultado}

Endpoints asíncronos - para operaciones con espera:

@app.get("/datos-externos")
async def obtener_datos_externos():
    # Simula llamada a API externa
    await asyncio.sleep(1)
    return {"datos": "Información obtenida de servicio externo"}

Manejo de múltiples operaciones asíncronas

Cuando necesitamos realizar múltiples operaciones asíncronas, Python proporciona herramientas para ejecutarlas de forma concurrente:

@app.get("/datos-completos/{user_id}")
async def obtener_datos_completos(user_id: int):
    # Ejecutar múltiples operaciones en paralelo
    usuario_task = obtener_usuario_bd(user_id)
    pedidos_task = obtener_pedidos_usuario(user_id)
    preferencias_task = obtener_preferencias_usuario(user_id)
    
    # Esperar a que todas las operaciones terminen
    usuario, pedidos, preferencias = await asyncio.gather(
        usuario_task,
        pedidos_task,
        preferencias_task
    )
    
    return {
        "usuario": usuario,
        "pedidos": pedidos,
        "preferencias": preferencias
    }

async def obtener_usuario_bd(user_id: int):
    await asyncio.sleep(0.1)  # Simula consulta BD
    return {"id": user_id, "nombre": "Usuario"}

async def obtener_pedidos_usuario(user_id: int):
    await asyncio.sleep(0.2)  # Simula consulta BD
    return [{"id": 1, "producto": "Laptop"}]

async def obtener_preferencias_usuario(user_id: int):
    await asyncio.sleep(0.15)  # Simula consulta BD
    return {"tema": "oscuro", "idioma": "es"}

En este ejemplo, las tres consultas se ejecutan concurrentemente en lugar de secuencialmente, reduciendo el tiempo total de respuesta de 0.45 segundos (0.1 + 0.2 + 0.15) a aproximadamente 0.2 segundos (el tiempo de la operación más lenta).

La asincronía en FastAPI no solo mejora el rendimiento de nuestras aplicaciones, sino que también proporciona una mejor experiencia de usuario al reducir los tiempos de espera y permitir que la aplicación responda de forma más fluida a múltiples peticiones simultáneas.

Empezar curso de FastAPI

Lecciones de este módulo de FastAPI

Lecciones de programación del módulo Asincronía del curso de FastAPI.