Em Elixir, todo código roda dentro de processos. Processos Elixir:
Por padrão, uma função é executada no mesmo processo de onde foi chamada. Quando você precisa executar explicitamente uma função específica em um novo processo, use spawn:
spawn/1 aceita uma função e a executa diretamente.
spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>
spawn/3 aceita o nome de um módulo, o nome de uma função (como átomo) e uma lista de argumentos, e executa essa função.
spawn(String, :split, ["hello there", " "])
# => #PID<0.113.0>
Um processo termina assim que sua função termina de executar.
Você pode verificar se um processo ainda está vivo (executando) com Process.alive?/1:
pid = spawn(fn -> 2 + 2 end)
Process.alive?(pid)
# => false
Processos não compartilham informações diretamente uns com os outros. Processos enviam mensagens para compartilhar dados. Esse padrão de concorrência é chamado de modelo de ator.
Envie mensagens para um processo usando send/2.
send(pid, :hello)
send não verifica se a mensagem foi recebida nem se o destinatário ainda está vivo.Uma mensagem pode ser de qualquer tipo.
Você pode receber uma mensagem enviada ao processo atual usando receive/1.
receive espera até que uma mensagem que corresponda a algum dos padrões esteja na caixa de mensagens do processo.
after._ que captura tudo em receive/1 para evitar ficar sem memória devido a mensagens não lidas acumuladas.receive do
{:ping, sender_pid} -> send(sender_pid, :pong)
_ -> nil
after
5000 ->
{:error, "No message in 5 seconds"}
end
Se você quer receber mais de uma mensagem, precisa chamar receive/1 recursivamente. É um padrão comum implementar uma função recursiva, por exemplo chamada loop, que chama receive/1, faz algo com a mensagem e depois se chama para esperar mais mensagens. Se você precisa carregar algum estado de uma chamada de receive/1 para outra, pode fazer isso passando um argumento para essa função 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
Na prática, essa abordagem raramente é usada diretamente. Elixir oferece abstrações de concorrência, como o módulo Agent ou o comportamento GenServer, que ambos são construídos sobre o laço de recebimento. No entanto, é crucial entender esses fundamentos para poder usar as abstrações de forma eficiente.