Django LiveView vs Phoenix LiveView: auténtico rendimiento
Tenía curiosidad: ¿cómo se comporta Django LiveView frente a la implementación original de Elixir cuando los comparas en condiciones idénticas? No con argumentos teóricos, sino con números reales.
Monté un dashboard de alertas idéntico en ambos frameworks: añadir, borrar y buscar alertas en tiempo real. El benchmark lo automaticé con Playwright headless Chromium para medir el tiempo entre la acción del usuario y el cambio en el DOM, más los bytes enviados por WebSocket en cada interacción.
El código fuente está en el repositorio y es completamente reproducible con Docker Compose.
Veamos los resultados.
El stack
| Componente | Django LiveView | Phoenix LiveView |
|---|---|---|
| Lenguaje | Python 3.12 | Elixir 1.17.3 / OTP 27 |
| Framework | Django 6.0.5 | Phoenix 1.7 |
| LiveView | django-liveview 2.2.0 | phoenix_live_view 1.0 |
| Servidor | Uvicorn 0.47.0 | Bandit 1.5 |
| WS layer | Channels 4.3.2 + Redis 7 | BEAM (built-in) |
Escenarios comunes
Medí 10 iteraciones (2 de warmup) para add, delete y search sobre una lista con pocos elementos.
/https://andros.dev/media/blog/2026/05/latency_common.png)
| Escenario | Django LiveView avg (ms) | Phoenix avg (ms) |
|---|---|---|
| Add alert | 21,91 | 22,69 |
| Delete alert | 21,71 | 22,44 |
| Search / filter | 6,46 | 7,97 |
Empate total. Ambos se mueven en el mismo rango de ~22 ms para mutaciones y ~7 ms para búsqueda. La diferencia es estadísticamente irrelevante.
/https://andros.dev/media/blog/2026/05/distribution_common.png)
Casos extremos
Aquí empieza a aparecer algo interesante.
/https://andros.dev/media/blog/2026/05/latency_edge.png)
| Escenario | Django avg (ms) | Phoenix avg (ms) |
|---|---|---|
| Lista grande (500 items) | 52,84 | 49,70 |
| Rapid fire (5 clicks) | 270,42 | 274,36 |
| Búsqueda vacía | 6,56 | 8,16 |
Con 500 alertas cargadas, Phoenix es ligeramente más rápido. El rapid fire es prácticamente idéntico.
Sin embargo... el dato más llamativo es el payload:
/https://andros.dev/media/blog/2026/05/payload.png)
| Escenario | Django recibe | Phoenix recibe |
|---|---|---|
| Add alert | 5.343 B | 1.236 B |
| Delete alert | 3.419 B | 735 B |
| Search / filter | 4.345 B | 698 B |
| Lista grande (500 items) | 327.495 B | 67.131 B |
| Rapid fire (5 clicks) | 60.822 B | 12.466 B |
En la lista grande, Django LiveView transfiere 327 KB por acción frente a los 67 KB de Phoenix. Cada vez que añades una alerta con 500 ya cargadas, Django LiveView vuelve a enviarte la tabla entera. Phoenix solo te manda la fila nueva.
Es una diferencia de diseño, no de implementación. En Django LiveView defines explícitamente qué selector actualizar y con qué HTML:
@liveview_handler("add_alert")
def add_alert(consumer, content):
alerts = list(Alert.objects.all())
html = render_to_string("components/_alerts_table.html", {"alerts": alerts})
send(consumer, {"target": "#alerts-container", "html": html})
En Phoenix LiveView actualizas los assigns y el framework calcula el diff:
def handle_event("add_alert", _params, socket) do
alert = Alerts.create_random_alert()
{:noreply, assign(socket, alerts: [alert | socket.assigns.alerts])}
end
Phoenix sabe qué parte del template cambió y solo manda eso. Django LiveView no tiene ese mecanismo, así que la granularidad depende de ti: si apuntas a un selector pequeño, envías menos. Si apuntas a un contenedor grande, envías todo. ¿Esto tiene consecuencias? En conexiones lentas o con muchos clientes simultáneos, sí. En una app con pocos usuarios o con listas pequeñas, será indistinguible.
Concurrencia
¿Qué pasa cuando varios usuarios actúan al mismo tiempo? Lancé entre 1 y 50 clientes simultáneos disparando la misma acción a la vez con una barrera de sincronización.
/https://andros.dev/media/blog/2026/05/concurrency.png)
| Clientes | Django add p50 | Phoenix add p50 | Django search p50 | Phoenix search p50 |
|---|---|---|---|---|
| 1 | 18,4 ms | 21,4 ms | 10,5 ms | 13,6 ms |
| 5 | 24,6 ms | 29,3 ms | 17,1 ms | 23,2 ms |
| 10 | 56,0 ms | 52,8 ms | 31,4 ms | 38,0 ms |
| 25 | 239,9 ms | 85,8 ms | 85,5 ms | 109,2 ms |
| 50 | 483,0 ms | 243,8 ms | 303,6 ms | 326,6 ms |
Con pocos clientes (1-5) ambos se comportan igual, incluso Django es ligeramente más rápido en p50. A partir de 25 clientes simultáneos la diferencia es clara: Phoenix escala mejor, especialmente en add_alert donde con 50 clientes Django dobla la latencia de Phoenix.
Conclusión
Los datos resuelven mi pregunta inicial: "¿Django LiveView aguanta la comparación con Phoenix LiveView?", la respuesta es sí, en operaciones del día a día son prácticamente iguales. La ventaja de Phoenix aparece cuando el payload crece o cuando la concurrencia es alta, aunque son problemas que puedes mitigar con un diseño cuidadoso en Django LiveView, apuntando a selectores más específicos y distribuyendo la carga.
La ventaja de Django LiveView es quedarte en Python y en el ecosistema Django, sin salir de lo que ya conoces, y que Django LiveView es más explícito y predecible: tú decides qué HTML enviar y dónde colocarlo.
Estoy gratamente sorprendido.
PD: Estás ante un sitio realizado 100% con Django LiveView, te invito a probar sus límites.
Este trabajo está bajo una licencia Attribution-NonCommercial-NoDerivatives 4.0 International.
Apóyame en Ko-fi
Comentarios
Todavía no hay ningún comentario.