প্

প্রসেস মধ্যে Elixir

5টি অনুশীলনী

প্রসেস সম্পর্কে

Elixir-এ সমস্ত কোড প্রসেসের ভিতরে চলে। 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>
    
    • এই ডেটা ট্রিপলেটকে প্রায়ই MFA বলা হয়: Module, Function, Arguments (অর্থাৎ মডিউল, ফাংশন, আর্গুমেন্ট)।
  • একটি প্রসেস তার ফাংশন এক্সিকিউট করা শেষ হওয়ামাত্রই এক্সিট করে।

  • Process.alive?/1 দিয়ে আপনি পরীক্ষা করতে পারেন একটি প্রসেস এখনও সক্রিয় (এক্সিকিউট করছে) আছে কি না:

    pid = spawn(fn -> 2 + 2 end)
    Process.alive?(pid)
    # => false
    

মেসেজ

প্রসেসগুলো একে অপরের সাথে সরাসরি তথ্য শেয়ার করে না। ডেটা শেয়ার করার জন্য প্রসেসগুলো মেসেজ পাঠায়। এই কনকারেন্সি প্যাটার্নকে অ্যাক্টর মডেল বলা হয়।

  • 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 বিহেভিয়ার, যেগুলো দুটোই রিসিভ লুপের উপরে তৈরি। তবে অ্যাবস্ট্রাকশনগুলো দক্ষভাবে ব্যবহার করতে পারার জন্য ওই বেসিকগুলো বোঝা অত্যন্ত জরুরি।

GitHub-এর মাধ্যমে সম্পাদনা করুন লিংকটি নতুন একটি উইন্ডো বা ট্যাবে খুলবে

প্রসেস শিখুন

অনুশীলন লক করা আছে

প্রসেস অনুশীলন করতে আরও 4টি অনুশীলনী আনলক করুন