

Descubra más de La Naturaleza del Software
En el verano, cuando volvimos del campo trajimos algunas frutas de nuestro huerto a Santiago. Cuando veníamos a mitad de camino una hormiguita apareció caminando por el volante de mi auto. Entonces conversamos con Kika sobre el pobre destino de esta hormiga solitaria, pues la habíamos alejado de su hormiguero. Ya no podría volver a su casa con sus hermanas, y eso es algo triste.
Pero aparte de esto, lo que sabemos de las hormigas, gracias al trabajo de personas como Edward Osborne Wilson es que son animales cooperadores y que efectivamente, para una hormiga quedar sola es una sentencia de muerte.
Ahora bien, cuando Hewitt discute sobre su modelo nos recuerda que lo mismo pasa con los actores. Para entender el modelo de actores, tenemos que entender que no tiene sentido hablar de un actor aislado. Los actores están siempre cooperando con otros actores dentro de un sistema. Pero me estoy adelantando, vamos explicar de que se trata esto de los actores, y recordar por qué llegamos a esta discusión.
En los artículos previos he estado comentando una charla de Douglas Crockford que dio el año pasado, en que propone un lenguaje para el futuro. En la parte central de su ponencia este autor presenta el modelo de actores, inventado en los años setenta por Carl Hewitt. Con esto lo que propone Crockford es superar las abstracciones para la programación concurrente, que en opinión de este autor, dificultan la programación de este tipo, labor que es necesaria en el mundo actual, donde la concurrencia es esencial.
Entonces, antes de finalizar esta serie, voy a exponer brevemente de qué se trata el modelo de actores y les dejaré un gran video en que pueden ver a Hewitt discutiendo su modelo con otros dos brillantes investigadores (Meijer y Szyperski).
Primero, para Hewitt el actor es la unidad fundamental de computación. Como tal tiene que contener tres cosas:
El procesamiento, porque se encarga de realizar alguna labor
El almacenamiento, porque para realizar su labor el actor tiene que ser capaz de recordar lo que ha estado haciendo (esto nos recuerda la noción de estado)
Las comunicaciones, es decir, tiene que tener la capacidad de intercambiar información con otros actores
Para Hewitt estos son los tres elementos esenciales de la computación: procesar, almacenar y comunicar.
Ahora bien, al igual que las hormigas, los actores no viven solos, están dentro de un sistema, un sistema en que todas las cosas son actores. Esto puede llevar a problemas, como por ejemplo, si decimos que un actor tiene una casilla de mensajes (mailbox), podemos considerar esta casilla como otro actor, lo que nos puede llevar a extrañas definiciones recursivas, o como dice Hewitt, al desastre.
Entonces para ordenar todo establece unos axiomas, que son los siguientes:
Primero, los actores tiene una dirección, que se usa para enviar los mensajes.
Cuando un actor recibe un mensaje el puede:
Crear más actores
Puede enviar mensajes a los actores (si conoce sus direcciones)
Puede designar que es lo que hará con el próximo mensaje que reciba
No se asume ninguna secuencia para estas tres acciones, pueden ser ejecutadas una tras otra, o en paralelo, e incluso puede omitir algunas.
Y a partir de estos axiomas se tiene que construir todo lo demás.
Vamos a ver esto con un ejemplo muy sencillo en Elixir.
defmodule Stack do
def start(initial_stack) do
spawn_link fn ->
:global.register_name :custom_server, self
listen initial_stack
end
end
def listen(stack) do
receive do
{sender, :pop} -> handle_pop(sender, stack)
{sender, :push, value} -> listen([value|stack])
end
end
def handle_pop(sender, []) do
send sender, nil
listen []
end
def handle_pop(sender, stack) do
send sender, hd(stack)
listen tl(stack)
end
end
iex> {:ok, pid} = Stack.start([])
{:ok, ...}
iex> sender pid, {self(), :pop}
nil
iex> sender pid, {self(), :push, 7}
iex> sender pid, {self(), :pop}
7
En este ejemplo hemos creado un actor que maneja un stack (que recibe como parámetro al ser creado por primera vez usando la función start. En este caso estamos usando el soporte provisto por OTP que es el framework que permite simplificar el uso de actores en Elixir y Erlang.
Lo que hace spawn_link
es iniciar un proceso y registrarlo. En este proceso queda ejecutándose la función listen, que al invocar la primitiva receive
se bloquea esperando un mensaje. Los mensajes que conoce este actor son :pop
y :push
. Estos mensajes son manejados por las respectivas funciones, que recursivamente terminan llamando a la función listen
nuevamente.
Como está asegurado que cada actor recibe un mensaje a la vez, sabemos que estas operaciones serán procesadas una a la vez en este caso. Pero no tiene por que ser siempre así, y esto se puede complicar aún más, pero esa discusión va más allá del objetivo de este post.
Lo que me interesa que les quede son los principios y axiomas detrás del modelo de actores. Este modelo de manejo de concurrencia es muy poderoso y vale la pena entenderlo, y para que puedan profundizar les dejo más abajo un video con la participación de Hewitt.
Si este tema les interesa y hay interés, manifestado en likes y comentarios, puedo preparar un podcast y video en YouTube con un invitado que sabe de estos temas con quien podemos profundizar.