Az Elixirben minden kód folyamatokon belül fut. Az Elixir folyamatai:
Alapértelmezés szerint egy függvény ugyanabban a folyamatban fut le, amelyikből meghívták. Amikor egy adott függvényt kifejezetten egy új folyamatban szeretnél futtatni, használd a spawn-t:
A spawn/1 egy függvényt vár, amelyet közvetlenül végrehajt.
spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>
A spawn/3 egy függvényt vár, amelyet a modul neve, a függvény neve (atomként) és a függvénynek átadandó argumentumok listája alapján hajt végre.
spawn(String, :split, ["hello there", " "])
# => #PID<0.113.0>
Egy folyamat azonnal kilép, amint a függvénye befejezte a futását.
A Process.alive?/1 segítségével ellenőrizheted, hogy egy folyamat még él-e (fut-e):
pid = spawn(fn -> 2 + 2 end)
Process.alive?(pid)
# => false
A folyamatok nem osztanak meg egymással információt közvetlenül. Az adatok megosztásához üzeneteket küldenek egymásnak. Ez a párhuzamossági minta az úgynevezett Actor model.
Üzenetet küldhetsz egy folyamatnak a send/2 segítségével.
send(pid, :hello)
send nem ellenőrzi, hogy megérkezett-e az üzenet, és azt sem, hogy a címzett még él-e.Az üzenet bármilyen típusú lehet.
Az aktuális folyamatnak küldött üzenetet a receive/1 segítségével fogadhatod.
receive addig vár, amíg egy, a megadott minták valamelyikére illeszkedő üzenet meg nem jelenik a folyamat postaládájában.
after blokkal időtúllépést adhatsz neki._ ágat a receive/1-ben, hogy elkerüld a memóriahiányt a felhalmozódó olvasatlan üzenetek miatt.receive do
{:ping, sender_pid} -> send(sender_pid, :pong)
_ -> nil
after
5000 ->
{:error, "No message in 5 seconds"}
end
Ha egynél több üzenetet szeretnél fogadni, rekurzívan kell meghívnod a receive/1-et. Gyakori minta egy rekurzív függvény megvalósítása, például loop néven, amely meghívja a receive/1-et, tesz valamit az üzenettel, majd újra meghívja önmagát, hogy további üzenetekre várjon. Ha állapotot kell átvinned az egyik receive/1 hívásból a másikba, azt úgy teheted meg, hogy argumentumot adsz át a loop függvénynek.
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
A gyakorlatban ezt a megközelítést ritkán használják közvetlenül. Az Elixir párhuzamossági absztrakciókat kínál, például az Agent modult vagy a GenServer viselkedést, amelyek mind a fogadóciklusra épülnek. Ugyanakkor kulcsfontosságú megérteni ezeket az alapokat ahhoz, hogy hatékonyan tudd használni az absztrakciókat.