WSGI y ASGI son interfaces entre una aplicación web Python y el servidor que recibe conexiones. WSGI se diseñó para peticiones y respuestas HTTP síncronas. ASGI soporta ese modelo y también conexiones asíncronas persistentes, como WebSockets y streaming. La respuesta breve: conserva WSGI para aplicaciones síncronas maduras sin requisitos de tiempo real; elige ASGI cuando el framework, las bibliotecas y la carga se benefician de concurrencia asíncrona o protocolos persistentes.

No son frameworks ni servidores. Django, Flask y FastAPI son frameworks; Gunicorn, uWSGI, Uvicorn, Daphne y Hypercorn sirven aplicaciones. WSGI o ASGI define el contrato entre ambas capas. La PEP 3333 especifica WSGI y la especificación oficial ASGI define el protocolo asíncrono.

Cómo funciona WSGI

Un servidor WSGI llama a un objeto Python con environ y start_response. La aplicación devuelve un iterable de bytes. Cada llamada representa una petición HTTP y ocupa al worker mientras el código ejecuta o espera I/O. Esta interfaz simple creó un ecosistema estable, fácil de razonar y adecuado para muchos sitios.

def application(environ, start_response):
    body = b"Hello, WSGI!"
    start_response("200 OK", [
        ("Content-Type", "text/plain; charset=utf-8"),
        ("Content-Length", str(len(body))),
    ])
    return [body]

La concurrencia WSGI suele provenir de varios procesos o hilos. Si una consulta tarda, ese worker espera, pero otros atienden tráfico. Esto no hace que WSGI sea lento por definición. En CRUD, plantillas y aplicaciones dominadas por la base de datos, consultas, caché y buen código suelen importar más que cambiar la interfaz. Nuestra guía de desarrollo web con Python presenta el ecosistema.

Cómo funciona ASGI

Un servidor ASGI llama a una aplicación asíncrona con scope, receive y send. El scope describe la conexión; los eventos entran y salen mediante funciones awaitable. Este modelo representa HTTP, WebSocket y el ciclo de vida sin retener un hilo bloqueado por cada conexión inactiva.

async def application(scope, receive, send):
    assert scope["type"] == "http"
    await send({
        "type": "http.response.start",
        "status": 200,
        "headers": [[b"content-type", b"text/plain"]],
    })
    await send({
        "type": "http.response.body",
        "body": b"Hello, ASGI!",
    })

Cuando una coroutine espera I/O de red no bloqueante, el event loop avanza otras conexiones. Esto favorece muchas esperas simultáneas, streaming y tiempo real. No acelera CPU ni convierte bibliotecas síncronas en asíncronas. Consulta async y await en Python para comprender la ejecución.

Diferencias de arquitectura

  • Protocolos: WSGI modela HTTP; ASGI modela HTTP, WebSocket y ciclo de vida.
  • Ejecución: WSGI invoca código síncrono; ASGI admite código async y puede adaptar handlers síncronos.
  • Conexiones largas: WSGI permite streaming limitado, pero WebSocket queda fuera; ASGI representa ambos directamente.
  • Concurrencia: WSGI escala con procesos e hilos; ASGI añade multiplexación de I/O por event loop.
  • Complejidad: WSGI tiene menos fronteras; ASGI exige controlar bloqueos, cancelación y recursos compartidos.

ASGI no elimina workers. Cada proceso sigue limitado por CPU, memoria y event loop; varios procesos aportan paralelismo y aislamiento. Tampoco garantiza mayor throughput. Mide una carga representativa con base de datos y servicios externos, no una ruta “hello world”.

También considera la capacidad del equipo. Mantener una pila síncrona conocida puede ser más seguro que adoptar async sin experiencia operativa. La arquitectura debe reducir riesgos reales, no perseguir una etiqueta moderna.

Elegir según el caso

Prefiere WSGI si la aplicación es completamente síncrona, depende de bibliotecas bloqueantes, no necesita WebSockets y cumple sus objetivos. Un sitio Django tradicional o una API Flask con consultas comunes puede seguir en WSGI sin deuda técnica. Revisa la guía de API REST con Flask.

Prefiere ASGI para WebSockets, server-sent events, streaming, long polling o muchas llamadas de red concurrentes con clientes async. FastAPI y Starlette nacieron para ASGI; nuestra guía de FastAPI muestra el modelo. Para tráfico bidireccional, consulta WebSockets con Python.

Ninguna interfaz es una cola durable. Envío de correos, conversión de vídeo o informes grandes deben ejecutarse en un sistema de tareas si han de sobrevivir a reinicios. Crear una coroutine dentro de ASGI puede perder el trabajo durante un deploy y competir con el tráfico.

Django bajo WSGI y ASGI

Django incluye wsgi.py y asgi.py. ASGI habilita views async y conexiones asíncronas cuando el resto de la pila lo permite. Un middleware síncrono puede provocar adaptaciones y reducir la ventaja. Django documenta por separado el despliegue WSGI y el despliegue ASGI.

Antes de migrar, inventaría middleware, driver de base, caché, autenticación y clientes HTTP. Usa versiones async cuando corresponda y evita llamadas bloqueantes en el event loop. Django adapta estilos, pero cambios frecuentes agregan coste y complejidad. Nuestra guía completa de Django cubre la estructura.

Servidores y despliegue

Gunicorn es una elección WSGI común en Unix, a menudo detrás de un proxy inverso. Uvicorn, Daphne y Hypercorn implementan ASGI. Gunicorn también puede supervisar workers ASGI compatibles, según la documentación de las versiones instaladas. En Windows, usa un servidor que declare soporte para ese entorno.

El proxy suele terminar TLS, imponer límites y timeouts y reenviar metadatos confiables. Configura IP y esquema deliberadamente; no confíes en cabeceras reenviadas por clientes arbitrarios. Añade apagado gradual, health checks, límites y métricas. Para WebSockets, verifica upgrade y tiempos de inactividad en proxy, balanceador y servidor.

Errores frecuentes

  • Migrar a ASGI esperando acelerar CPU o SQL lento.
  • Llamar requests, drivers síncronos o funciones pesadas directamente desde una view async.
  • Ejecutar el servidor de desarrollo en producción.
  • Suponer que un event loop elimina procesos y límites de concurrencia.
  • Migrar sin auditar middleware y fronteras sync/async.
  • Usar tareas internas para trabajo que requiere entrega confiable.

Mide latencia por percentil, throughput, errores, CPU, conexiones y saturación de la base. Prueba desconexiones y cancelación en streaming. Una aplicación ASGI que bloquea el loop puede rendir peor que un despliegue WSGI bien dimensionado.

Preguntas frecuentes

¿ASGI siempre es más rápido que WSGI?

No. ASGI gestiona bien muchas esperas concurrentes, pero la base, el código, la configuración y la carga determinan el resultado. CPU sigue necesitando procesos o jobs.

¿Puedo ejecutar una aplicación WSGI en un servidor ASGI?

Existen adaptadores, pero no vuelven asíncrono el código y pueden añadir coste. Prefiere la interfaz nativa del framework cuando sea posible.

¿Django necesita ASGI para views async?

WSGI puede adaptarlas, pero una pila ASGI conserva mejor los beneficios de conexiones async y protocolos de larga duración.

¿Qué interfaz conviene en un proyecto nuevo?

Sigue la interfaz principal del framework y los requisitos. FastAPI implica ASGI; un Django síncrono puede usar cualquiera sin migrar por tendencia.

Conclusión

WSGI sigue siendo sólido para HTTP síncrono. ASGI amplía el contrato a concurrencia asíncrona, streaming y WebSockets, pero requiere una pila no bloqueante y operación cuidadosa. Decide por protocolos y perfil de espera, audita bibliotecas, despliega un servidor apropiado y mide tráfico real. La mejor opción es la más simple que cumple requisitos sin ocultar cuellos de botella.