3 min de lectura

La facilidad de async/await oculta una trampa en producción

Una nueva crítica sostiene que async/await hace el código fácil de escribir pero difícil de ejecutar, sobre todo cuando la E/S y las tareas intensivas en CPU colisionan.

Imagen: Hacker News

async/await conquistó a los desarrolladores al hacer que el código asíncrono pareciera código secuencial ordinario. Pero en un ensayo reciente, Philip Banugo sostiene que esa conveniencia enmascara una profunda complejidad operativa, especialmente en sistemas de producción construidos sobre runtimes cooperativos como Tokio de Rust y Node.js.

Su tesis central es que la asincronía y la concurrencia no son lo mismo, y que async/await difumina esa línea. En la práctica, eso puede convertirse en una trampa de rendimiento: un desarrollador escribe una función async que obtiene datos por la red y luego realiza trabajo intensivo en la CPU —analizar una carga JSON de 10 MB, recorrer una colección grande o ejecutar código criptográfico. En un ejecutor cooperativo, ese trabajo no cede hasta alcanzar otro await, por lo que una tarea ligada a la CPU de 50 milisegundos puede detener todo el hilo de ejecución y aumentar la latencia de solicitudes no relacionadas.

Banugo señala una solución habitual en producción: dividir responsabilidades entre runtimes, usando Tokio para E/S y un pool de hilos como Rayon para tareas intensivas en cómputo. Pero afirma que esa solución genera otro problema. Los equipos deben decidir manualmente qué funciones pertenecen al “pool de E/S” y cuáles al “pool de Cómputo”, y luego mantener límites de paso de mensajes entre ambos. Cita postmortems de PostHog Engineering y Meilisearch como ejemplos de lo doloroso que puede volverse ese desenredo.

Una segunda crítica apunta al comportamiento predeterminado en muchos ecosistemas asíncronos. Debido a que llamadas como tokio::spawn(…) son baratas y las colas de tareas suelen ser efectivamente ilimitadas, los sistemas sobrecargados pueden seguir aceptando trabajo en lugar de aplicar retropresión. El resultado, escribe Banugo, es una cola que crece hasta que la memoria se agota y el OOM killer del sistema operativo termina el proceso.

Recomendado

El impulso europeo en chips no acabará con la dependencia de la nube estadounidense

Por qué el robo de tareas puede perjudicar a gran escala

Banugo también arremete contra los planificadores de robo de tareas, que a menudo se presentan como una forma más inteligente de balancear la carga entre núcleos. Sostiene que, a muy altos recuentos de núcleos, la equidad puede ir en detrimento del rendimiento porque mover tareas entre núcleos destruye la localidad de la caché de la CPU. Cita el relato de Robin Morisset sobre WhatsApp llevando el planificador BEAM de Erlang a máquinas de más de 100 núcleos, donde la contención por el runq_lock global se convirtió en un cuello de botella.

El modelo hilo-por-núcleo del Proyecto Tina

Como alternativa, Banugo presenta Project Tina, un framework de concurrencia de código abierto hilo-por-núcleo y sin memoria compartida. En lugar de funciones async, promesas o futuros, Tina usa Isolates —unidades de trabajo concurrente que procesan mensajes de forma sincrónica y devuelven un Effect.

Describe Tina con algunas reglas estrictas:

  • Sin async/await, promesas ni futuros
  • Sin robo de tareas
  • Sin memoria compartida ni mutexes
  • Memoria preasignada al arrancar el proceso
  • Buzones estrictamente acotados

Ese diseño, argumenta, hace que la sobrecarga sea explícita: cuando un buzón está lleno, el llamador recibe retroalimentación inmediata en lugar de encolar trabajo silenciosamente hasta que el proceso se bloquee. Banugo dice que la recompensa es un comportamiento determinista, incluyendo Pruebas de Simulación Determinista (DST), donde la misma semilla produce el mismo orden de ejecución cada vez.

Su conclusión es contundente: async/await hace que la concurrencia sea más fácil de escribir, pero más difícil de operar. Tina apuesta a que restricciones más estrictas y una planificación visible son un mejor compromiso que la magia del runtime.

Marcus Vance

Enterprise Editor

Marcus follows the money. He covers enterprise software, cloud architecture, and the tectonic shifts in Big Tech strategy. He translates dense earnings calls and complex M&A activity into actionable insights about where the industry is actually heading. If a tech giant makes a silent pivot, Marcus is usually the first to notice.

vía Hacker News

// Sigue leyendo