در Elixir، همهی کدها داخل فرایندها اجرا میشوند. فرایندهای Elixir:
بهطور پیشفرض، یک تابع در همان فرایندی اجرا میشود که از آن فراخوانی شده است. وقتی لازم است تابع خاصی را بهطور صریح در فرایند جدیدی اجرا کنید، از spawn استفاده کنید:
spawn/1 تابعی را میپذیرد که آن را مستقیماً اجرا میکند.
spawn(fn -> 2 + 2 end)
# => #PID<0.125.0>
spawn/3 تابعی را میپذیرد که آن را با اسم ماژول، اسم تابع (بهصورت «اتم») و فهرستی از آرگومانهایی که به آن تابع داده میشوند اجرا میکند.
spawn(String, :split, ["hello there", " "])
# => #PID<0.113.0>
یک فرایند بهمحض اینکه اجرای تابعش تمام شود، پایان مییابد.
میتوانید با Process.alive?/1 بررسی کنید که آیا فرایندی هنوز زنده (در حال اجرا) است:
pid = spawn(fn -> 2 + 2 end)
Process.alive?(pid)
# => false
فرایندها اطلاعات را مستقیماً با یکدیگر به اشتراک نمیگذارند. فرایندها برای به اشتراک گذاشتن داده، پیام میفرستند. به این الگوی همروندی، «مدل Actor» میگویند.
با send/2 به یک فرایند پیام بفرستید.
send(pid, :hello)
send بررسی نمیکند که پیام دریافت شده است یا نه، و نه اینکه گیرنده هنوز زنده است یا نه.پیام میتواند از هر نوعی باشد.
میتوانید پیامی را که به فرایند جاری فرستاده شده، با receive/1 دریافت کنید.
receive صبر میکند تا پیامی که با یکی از الگوهای دادهشده تطبیق داشته باشد در صندوق پیام فرایند قرار بگیرد.
after برایش مهلت زمانی تعیین کرد.receive/1 یک بند جامع _ بنویسید تا به دلیل انباشته شدن پیامهای خواندهنشده، حافظه تمام نشود.receive do
{:ping, sender_pid} -> send(sender_pid, :pong)
_ -> nil
after
5000 ->
{:error, "No message in 5 seconds"}
end
اگر میخواهید بیش از یک پیام دریافت کنید، باید receive/1 را بهصورت بازگشتی فراخوانی کنید. الگوی رایجی است که یک تابع بازگشتی پیادهسازی کنید، مثلاً با اسم loop، که receive/1 را فراخوانی میکند، کاری با پیام انجام میدهد و سپس خودش را فراخوانی میکند تا منتظر پیامهای بیشتری بماند. اگر لازم است حالتی را از یک فراخوانی receive/1 به فراخوانی دیگر منتقل کنید، میتوانید این کار را با دادن یک آرگومان به آن تابع 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
در عمل، این روش بهندرت مستقیماً استفاده میشود. Elixir انتزاعهای همروندی ارائه میدهد، مانند ماژول Agent یا رفتار GenServer، که هر دو روی حلقهی دریافت ساخته شدهاند. با این حال، درک این مبانی برای استفادهی کارآمد از این انتزاعها ضروری است.