En Elixir, todo el código se ejecuta dentro de procesos.
De forma predeterminada, una función se ejecuta en el mismo proceso desde el que se llamó. Cuando necesitas ejecutar explícitamente una función determinada en un proceso nuevo, usa spawn/1:
spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>
spawn/1 crea un proceso nuevo que ejecuta la función de aridad 0 que se le pasa y devuelve un identificador de proceso (PID). El proceso nuevo permanecerá vivo mientras se ejecute la función y luego terminará en silencio.
No debes confundir los procesos de Elixir con los procesos del sistema operativo. Los procesos de Elixir usan mucha menos memoria y CPU. No hay ningún problema en tener aplicaciones de Elixir que ejecuten cientos de procesos de Elixir.
Los procesos no comparten información directamente entre sí. Los procesos envían y reciben mensajes para compartir datos.
Puedes enviar un mensaje a cualquier proceso con send/2. El primer argumento de send/2 es el PID del destinatario y el segundo argumento es el mensaje.
Un mensaje puede ser de cualquier tipo. A menudo consiste en átomos y tuplas. Si quieres recibir una respuesta, debes incluir el PID del remitente en algún lugar del mensaje. Puedes obtener el PID del proceso actual con self().
send/2 no verifica si el destinatario recibió el mensaje ni si el destinatario sigue vivo. El mensaje termina en el buzón del destinatario y solo se leerá si el destinatario pide explícitamente recibir mensajes.
Un mensaje se puede leer de un buzón usando la macro receive/1. Acepta un bloque do en el que puedes hacer coincidencia de patrones con los mensajes.
receive do
{:ping, sender_pid} -> send(sender_pid, :pong)
:do_nothing -> nil
end
receive/1 tomará un mensaje del buzón que coincida con alguno de los patrones dados y ejecutará la expresión dada para ese patrón. Si no hay mensajes en el buzón, o ninguno de los mensajes del buzón coincide con alguno de los patrones, receive/1 esperará a uno.
Si quieres recibir más de un mensaje, debes llamar a receive/1 de forma recursiva. Es un patrón común implementar una función recursiva, por ejemplo llamada loop, que llama a receive/1, hace algo con el mensaje y luego se llama a sí misma para esperar más mensajes. Si necesitas conservar algún estado de una llamada a receive/1 a otra, puedes hacerlo pasando un argumento a esa función loop.
Los identificadores de proceso son su propio tipo de dato. Funcionan como direcciones de buzón: si tienes el PID de un proceso, puedes enviarle un mensaje a ese proceso. Por lo general, los PID se crean de forma indirecta, como valor de retorno de funciones que crean procesos nuevos, como spawn.
Estás escribiendo un sistema embebido para una máquina Take-A-Number. Es un modelo muy simple. Puede entregar números consecutivos e informar cuál fue el último número entregado.
Implementa la función start/0. Debe crear un nuevo proceso y devolver el PID del proceso. El nuevo proceso todavía no necesita hacer nada.
TakeANumber.start()
# => #PID<0.138.0>
Ten en cuenta que cada vez que ejecutes este código, el PID puede ser distinto.
Modifica la máquina para que el proceso recién creado esté listo para recibir mensajes (inicia un bucle de recepción) con un estado inicial de 0. Debe poder recibir mensajes {:report_state, sender_pid}. Como respuesta a esos mensajes, debe enviar su estado actual (el último turno entregado) a sender_pid y luego esperar más mensajes.
machine_pid = TakeANumber.start()
# a client sending a message to the machine
send(machine_pid, {:report_state, self()})
# a client receiving a message from the machine
receive do
msg -> msg
end
# => 0
Modifica la máquina para que pueda recibir mensajes {:take_a_number, sender_pid}. Debe aumentar su estado en 1, enviar el nuevo estado a sender_pid y luego esperar más mensajes.
machine_pid = TakeANumber.start()
# a client sending a message to the machine
send(machine_pid, {:take_a_number, self()})
# a client receiving a message from the machine
receive do
msg -> msg
end
# => 1
Modifica la máquina para que pueda recibir un mensaje :stop. Debe dejar de esperar más mensajes.
Modifica la máquina para que, cuando reciba un mensaje inesperado, lo ignore y siga esperando más mensajes.
Regístrate en Exercism para aprender y dominar Elixir con 58 conceptos168 ejercicios y mentoría humana real, todo gratis.