برنامه نویسی

فرآیند اکسیر، چیست؟ چگونه کار می کند؟ فرآیند مرتبط و نظارت شده

یکی از دشواری‌هایی که از زبان‌های دیگر به اکسیر می‌روند، فرآیند است و افراد معمولاً برای استفاده از کتابخانه آن را نادیده می‌گیرند.

در واقع، فرآیند اکسیر چیز بسیار قدرتمندی است، اگر با سیستم مقیاس بزرگ وارد کار شویم، باید کارهای زیادی را با فرآیند انجام دهیم.

من مدت زیادی با Erlang (همچنین Golang) کار کرده ام و روند یکی از جالب ترین چیزها برای من است.

از نظر من فرآیند اکسیر 3 نکته مهم برای مراقبت دارد.

  1. فرآیند کد ایزوله است (مانند یک جزیره) و ارسال/دریافت پیام راهی برای تعامل با دنیای خارج است. اگر فرآیند از بین برود، بر سایر فرآیندها تأثیر نمی گذارد (به جز یک مورد فرآیند مرتبط است).
  2. فرآیند را می توان برای دانستن نحوه خروج از فرآیند (:normal, :error,..) مانیتور کرد.
  3. فرآیند را می توان پیوند داد (با هم گروه بندی کرد) و تمام فرآیندهای مرتبط با فرآیند ناموفق از بین خواهند رفت (به جز این که فرآیند trap_exit را به true تبدیل کند).

از 3 مورد بالا، ما می‌توانیم چیزهای زیادی را با فرآیندهایی بسازیم: ایجاد یک مدل سرپرست/کارگر سفارشی، ساختن فرآیندهای استخری ساده برای به اشتراک گذاشتن حجم کار، ایجاد یک پردازش داده زنجیره‌ای، و…

اکنون برای درک مفهوم فرآیند اکسیر یکی یکی مرور می کنیم.

کد ایزوله در حال پردازش است

اگر نحوه عملکرد آن را درک کنیم، کار در اکسیر بسیار آسان تر است. از به اشتراک گذاری متغیرها (متغیرهای قابل تغییر) کمی احساس سختی برای آوردن الگوریتم ها به نظر می رسد (همچنین حلقه واقعی / در حالی که برای اکسیر). فقط تصور کنید که در یک جزیره تنها زندگی می کنید و فقط با یک راه ارتباط با بیرون از طریق ارسال پیام به یک بطری، اقیانوس به هر چیز دیگری اهمیت می دهد.
(در واقع، ما می توانیم حالت را به اشتراک بگذاریم :ets، :persistent_termیا پایگاه داده دیگری).

هنگامی که می خواهید پیامی ارسال کنید، پیامی را با آدرس به بطری قرار می دهید، سپس به ساحل بروید و بطری را به اقیانوس پرتاب کنید. با کمی زمان برای دوست خود پیامی دریافت خواهید کرد.
و هنگامی که می خواهید از جزایر دیگر پیامی دریافت کنید، به ساحل می روید و می بینید که آیا بطری در ساحل وجود دارد، بررسی کنید و سپس فقط پیامی را دریافت کنید که می خواهید دریافت کنید.

برای اقداماتی مانند سرور/مشتری، ما پیامی ارسال می کنیم و با گذشت زمان (یا برای همیشه) در ساحل می مانیم تا نتیجه بگیریم.

ارتباط بین دو فرآیند

برای ارسال کد استفاده می کنیم send/2 تابع:

send(pid, {:get, :user_info, self()})
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای دریافت پیام (از قبل در صندوق پستی یا منتظر پیام جدید) استفاده می کنیم receive do نحو درست مثل case do:

receive do
      {:user_info, data} ->
        IO.puts "user data: #{inspect data}"
      other ->
        IO.puts "other data: #{inspect other}"
end
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

می توانید قرار دهید receive do به یک تابع برای رفتن دوباره به حلقه اگر می خواهید مانند یک سرور پردازش کنید.

در صورتی که پیام با هیچ الگوی مطابقت نداشته باشد receive do آن را تا در صندوق پستی فرآیند باقی بماند. می‌توانید در آینده آن را دریافت کنید، اما باید مطمئن شوید که پیام‌های ناهمسان زیادی را برای پردازش فشار ندهید زیرا می‌تواند یک OMM ایجاد کند.

فرآیندهای پیوند

این ویژگی ویژگی بسیار قدرتمند اکسیر است. ما می توانیم گروهی از فرآیندها را برای انجام وظایف گروهی یا زنجیره ای از وظایف کنترل کنیم.

مثال:
فرآیند A –linked–> B –linked–> C

IO.puts "I'm A"

fun = fn ->
  receive do
    :shutdown ->
      IO.puts "exited"
    {:ping, from} ->
      IO.puts "got a ping from #{inspect from}"
      send(from, :pong)
    message ->
      IO.puts "Got a message: #{inspect message}"
  end
end

# spawn and link process B
spawn_link(fn ->
  IO.puts "I'm B"
  spawn_link(fn ->
    IO.puts "I'm C"

    fun.()
  end)

  fun.()
end)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از این کد، فرآیندها را در وظیفه زنجیره ای پیوند می دهیم. اگر هر فرآیندی با شکست مواجه شود، سایر فرآیندها نیز از بین خواهند رفت. ما نیازی به مراقبت برای تشخیص وظیفه دم/تمیز نداریم.
همه ما گروهی مانند:
رهبر فرآیند –linked–> worker1, worker2, …, workerN
و هر فرآیندی با شکست مواجه شود، تمام فرآیندهای دیگر به دنبال آن خواهند مرد.

trap_exit

در صورتی که نمی خواهیم فرآیندی از بین برود و به دنبال روند شکست خورده خود برویم، می‌توانیم آن را تغییر دهیم trap_exit روشن است (پرچم را روی true تنظیم کنید) و فرآیند یک پیام ناموفق دریافت می کند به جای اینکه به دنبال فرآیند ناموفق باشد.

Process.flag(:trap_exit, true)
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هنگامی که فرآیند شما با شکست مواجه شد، پیامی مانند زیر دریافت خواهد کرد.

{:EXIT, #PID<0.192.0>, {%RuntimeError{message: "#PID<0.192.0>, raise a RuntimeError :D"}, []}}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نظارت بر فرآیند

در موارد دیگر، ما فقط می‌خواهیم از این که چرا فرآیند دیگر از کار افتاده است، می‌توانیم استفاده کنیم monitor روند.

عملکردی برای فرآیند مانیتور داشته باشید: spawn_monitor، Process.monitor برای ساخت یک مانیتور به فرآیند دیگر.

برای حذف مانیتور می توانیم استفاده کنیم Process.demonitor.

اگر فرآیند نظارت شده با شکست مواجه شود، یک مانیتور فرآیند ساختن آن فرآیند پیامی مانند:

{:DOWN, #Reference<...>, :process, #PID<...>, reason}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از فرآیند پیوند/مانیتور می توانیم چیزهای زیادی برای سیستم خود بسازیم و می توانیم خوب بخوابیم! ما می توانیم یک سرپرست خاص، کارگران استخر خود،…

در این زمان من فقط یک توضیح اساسی دارم، در آینده جزئیات بیشتری را توضیح خواهم داد.

من LiveBook را برای مشابه آن دارم که می توانید یک نسخه نمایشی محتوا + منبع را در مخزن Github ما بررسی کنید

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا