Soporte Asíncrono en Django: cuándo usarlo, cómo funciona y cuándo NO conviene

- 👤 Andrés Cruz

🇺🇸 In english

Django siempre ha sido sinónimo de productividad: ORM potente, admin listo para producción y un ecosistema maduro. Sin embargo, durante años arrastró una fama difícil de ignorar: no destacar por rendimiento. Gran parte de esa percepción viene de su modelo síncrono por defecto.

Desde Django 3.x, el framework incorporó soporte asíncrono, y con ello surgió una pregunta muy habitual:

¿realmente vale la pena usar async en Django?

La respuesta corta es: depende del tipo de carga.

La respuesta larga es justo lo que vas a leer aquí.

¿Qué es el soporte asíncrono en Django?

El soporte asíncrono en Django permite definir vistas asíncronas (async def) y ejecutar toda la cadena de petición en modo asíncrono cuando la aplicación se despliega sobre ASGI (Asynchronous Server Gateway Interface).

En términos simples:

  • Django puede no bloquear el servidor mientras espera operaciones de E/S.
  • Un mismo worker puede atender muchas solicitudes concurrentes.
  • Es especialmente útil para llamadas a APIs externas, streaming, long-polling o bases de datos lentas.

Algo importante que suele pasar desapercibido:

Las vistas async también funcionan bajo WSGI, pero sin beneficios reales de rendimiento y con penalizaciones adicionales.

Django Sync vs Async: diferencias clave que importan de verdad

Modelo síncrono: cómo funciona y por qué limita el rendimiento

En el modelo tradicional (Sync):

  • Un worker → una petición a la vez.
  • Si la petición espera E/S (base de datos, red, disco), el worker queda bloqueado.
  • Para escalar, se agregan más threads o procesos… con más consumo de memoria.

En la práctica, esto hace que Django sufra especialmente cuando:

  • Hay latencia de red.
  • Se hacen muchas consultas a la base de datos.
  • Se depende de servicios externos.

Esto fue evidente al analizar endpoints que simplemente “esperaban” a la base de datos: el servidor estaba ocioso, pero no podía atender nuevas solicitudes.

Modelo asíncrono: multitarea colaborativa y concurrencia real

Con Async, el modelo cambia:

  • Un worker puede manejar muchas solicitudes al mismo tiempo.
  • Cuando una tarea llega a un await, libera el control.
  • Otras solicitudes avanzan mientras tanto.

Este enfoque se conoce como multitarea colaborativa y es mucho más eficiente que el cambio de contexto tradicional entre threads.

Eso sí: async no acelera el código por sí mismo.

Lo que hace es aprovechar mejor el tiempo muerto de E/S.

ASGI vs WSGI en Django: por qué el servidor importa

Qué ocurre si usas async bajo WSGI

Cuando ejecutas una vista async bajo WSGI:

  • Django crea un event loop “de emergencia”.
  • Puedes usar await, pero…
  • Cada request sigue usando un thread.

Resultado:

  • ✔ Funciona
  • ❌ No escala
  • ❌ No obtienes concurrencia real

Por qué ASGI desbloquea el verdadero rendimiento asíncrono

Para obtener beneficios reales necesitas:

  • ASGI
  • Un servidor como Uvicorn, Daphne o Hypercorn
  • Middleware compatible con async

Se puede usar en:

  • Cientos de conexiones concurrentes
  • WebSockets
  • Streaming lento
  • Long-polling

Pero ojo: un solo middleware síncrono obliga a Django a volver al modelo basado en threads, anulando gran parte de la ganancia.

Vistas asíncronas en Django: cómo se implementan

Vistas async con async def

Crear una vista asíncrona es trivial:

 
from django.http import JsonResponse async def mi_vista(request): return JsonResponse({"mensaje": "Hola desde async"}) 

Para operaciones de E/S, puedes usar librerías async-native como httpx, aiofiles, etc.

Clases, middleware y compatibilidad

En vistas basadas en clases:

  • Los métodos HTTP (get, post) pueden ser async def.
  • __init__ y as_view() siguen siendo síncronos.

Si necesitas usar partes de Django que aún son sync (como parte del ORM), debes usar:

 
from asgiref.sync import sync_to_async resultado = await sync_to_async(funcion_sync, thread_sensitive=True)()

Rendimiento real: qué pasa en cargas CPU-bound vs IO-bound

Por qué async rinde peor en tareas de CPU

En pruebas de carga con rutas CPU-bound:

  • Async mostró un comportamiento menos predecible.
  • Sync tuvo mayor estabilidad y más éxitos totales.
  • El event loop no puede paralelizar CPU intensiva.

Para cargas CPU-bound, Sync sigue siendo la mejor opción.

Por qué async multiplica el rendimiento en IO y alta latencia

En rutas IO-bound (lectura y escritura en base de datos):

  • Con latencia de 200 ms, async fue:
    • ~40× mejor en lecturas
    • ~230× mejor en escrituras
  • Sync se degradó rápidamente porque los workers quedaban esperando.

Esto confirma algo clave que aprendí probando:
la latencia es el peor enemigo del modelo síncrono.

Async, en cambio, aprovecha ese tiempo muerto.

Limitaciones actuales del soporte asíncrono en Django

El estado real del ORM asíncrono

El ORM async aún está en evolución:

  • No todo es 100% asíncrono.
  • Algunas operaciones siguen siendo sync internamente.
  • Hay que mezclar await con sync_to_async.

Funciona, pero requiere criterio.

Middleware síncrono y otros cuellos de botella

Otros puntos críticos:

  • Límite de conexiones a la base de datos (Postgres fue un factor clave).
  • Middleware no compatible con async.
  • Complejidad adicional en debugging.

Async no simplifica, optimiza.

¿Deberías usar soporte asíncrono en Django en tu proyecto?

Casos donde async tiene sentido

  • APIs que consumen otras APIs
  • Operaciones con alta latencia
  • Streaming o WebSockets
  • IO intensivo (DB, red, colas)
  • Servicios con alta concurrencia

Casos donde sync sigue siendo la mejor opción

  • Procesamiento pesado de CPU
  • Lógica simple y baja concurrencia
  • Apps pequeñas donde la complejidad no se justifica

Buenas prácticas para usar async en Django sin romper tu app

  • Usa async solo donde aporta valor
  • Mide antes y después
  • Evita mezclar middleware sync innecesario
  • Controla conexiones a la base de datos
  • No reemplaza a Celery: se complementan

Conclusión

El soporte asíncrono en Django no es una bala de plata, pero bien usado puede transformar por completo el rendimiento de una aplicación.

La regla práctica que me dejó la experimentación es simple:

CPU-bound → Sync
IO-bound → Async

Si entiendes esa diferencia y eliges bien, Django sigue siendo una opción extremadamente sólida incluso en escenarios de alta concurrencia.

FAQs rápidas

  • ¿Django es realmente asíncrono?
    • Sí, bajo ASGI y sin middleware síncrono.
  • ¿Necesito reescribir toda mi app en async?
    • No. Puedes mezclar vistas sync y async.
  • ¿Async reemplaza a Celery?
    • No. Async maneja concurrencia; Celery tareas en segundo plano.

Acepto recibir anuncios de interes sobre este Blog.

Descubre cuándo usar el soporte asíncrono en Django, diferencias entre Sync y Async, ASGI vs WSGI y cómo mejorar el rendimiento real de tu app.

| 👤 Andrés Cruz

🇺🇸 In english