En Elixir, todo el código se ejecuta dentro de procesos. Los procesos de Elixir:
De forma predeterminada, una función se ejecuta en el mismo proceso desde el cual fue llamada. Cuando necesitas ejecutar explícitamente una función determinada en un proceso nuevo, usa spawn:
spawn/1 acepta una función que ejecutará directamente.
spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>
spawn/3 acepta una función que ejecutará por el nombre del módulo, el nombre de la función (como átomo) y una lista de argumentos que se pasan a esa función.
spawn(String, :split, ["hello there", " "])
# => #PID<0.113.0>
Un proceso termina en cuanto su función ha terminado de ejecutarse.
Puedes comprobar si un proceso sigue vivo (ejecutándose) con Process.alive?/1:
pid = spawn(fn -> 2 + 2 end)
Process.alive?(pid)
# => false
Los procesos no comparten información directamente entre sí. Los procesos envían mensajes para compartir datos. Este patrón de concurrencia se llama el modelo de actores.
Envía mensajes a un proceso con send/2.
send(pid, :hello)
send no comprueba si el mensaje fue recibido ni si el destinatario sigue vivo.Un mensaje puede ser de cualquier tipo.
Puedes recibir un mensaje enviado al proceso actual con receive/1.
receive espera hasta que un mensaje que coincida con alguno de los patrones dados esté en el buzón del proceso.
after._ que capture todo en receive/1 para evitar quedarte sin memoria por la acumulación de mensajes no leídos.receive do
{:ping, sender_pid} -> send(sender_pid, :pong)
_ -> nil
after
5000 ->
{:error, "No message in 5 seconds"}
end
Si quieres recibir más de un mensaje, necesitas 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 llevar algún estado de una llamada a receive/1 a otra, puedes hacerlo pasando un argumento a esa función loop.
def loop(state) do
receive do
:increment_by_one ->
loop(state + 1)
{:report_state, sender_pid} ->
send(sender_pid, state)
loop(state)
:stop ->
nil
_ ->
loop(state)
end
end
En la práctica, este enfoque rara vez se usa directamente. Elixir ofrece abstracciones de concurrencia, como el módulo Agent o el comportamiento GenServer, que se construyen sobre el bucle de recepción. Sin embargo, es fundamental entender esas bases para poder usar las abstracciones de forma eficiente.