Este artículo de Variant Systems explora por qué los sistemas basados en procesos, como los que utiliza Erlang/Elixir (BEAM y OTP), siguen siendo relevantes y efectivos en la construcción de sistemas concurrentes y distribuidos, especialmente en el contexto de la inteligencia artificial y los agentes. La recurrencia de la reinvención de estos patrones en otros frameworks (como los que emergen en el ecosistema de Python para IA) subraya su validez fundamental.
El problema de la concurrencia se aborda principalmente de dos maneras: compartiendo estado con bloqueos (mutexes, semáforos) o utilizando el modelo de paso de mensajes entre procesos aislados. La primera opción, común en muchos lenguajes, es propensa a errores difíciles de depurar (race conditions) y a cuellos de botella por contención de bloqueos. El modelo de paso de mensajes, por otro lado, elimina la necesidad de bloqueos al garantizar que cada proceso tenga su propia memoria aislada. Esto se basa en el 'Actor Model', propuesto en 1973 e implementado en Erlang en 1986.
En BEAM, un 'proceso' no es un proceso del sistema operativo ni un hilo tradicional. Es una entidad ligera (~2KB de memoria) con su propio heap, pila y recolector de basura, lo que permite la creación de millones de procesos en una sola máquina sin pausas globales del recolector de basura. La programación es preemptiva, limitando el tiempo de CPU que un proceso puede usar, evitando así el monopolio de recursos. La clave es que los procesos solo pueden interactuar a través del paso de mensajes, lo que garantiza el aislamiento de la memoria y elimina la posibilidad de corrupción de datos.
Un aspecto crucial es el manejo de fallos. En BEAM, cuando un proceso falla, solo se detiene ese proceso; el resto del sistema continúa funcionando. Los mensajes se almacenan en una 'buzón' (mailbox) para cada proceso, permitiendo el procesamiento asíncrono y la implementación de mecanismos de 'backpressure' (control de flujo) para evitar la sobrecarga. La filosofía de 'dejar fallar' (let it crash) no implica ignorar los errores, sino separar el código que realiza el trabajo del código que gestiona los fallos, promoviendo un diseño más resiliente.
El artículo concluye que la combinación de procesos aislados, paso de mensajes y una filosofía de manejo de fallos robusta es difícil de replicar completamente en otras plataformas, lo que explica por qué los patrones de BEAM y OTP se reinventan constantemente.
