Golang এর Concurrency পর্ব -২

 গতপর্বে আমি কথা বলেছিলাম থ্রেড, প্রসেস, কনটেক্সট সুইচিং, CSP (Communicating Sequential Processes) নিয়ে। গতপর্বে আরো বিস্তারিত বলা উচিত ছিলো যেটা আসলে বলা হয়নি!

পর্ব ০ পূর্বের কিছু আলোচনা

ট্র্যাডিশনালি, যখন একটি প্রসেসের মধ্যে একাধিক থ্রেড চলে, তখন সেই থ্রেডগুলো একই মেমোরি স্পেস শেয়ার করে। এর ফলে গ্লোবাল ভেরিয়েবল বা হিপ মেমোরির মতো শেয়ার্ড ডেটায় অ্যাক্সেস করার সময় ডেটা রেস বা অসঙ্গতি এড়াতে লকিং মেকানিজম (যেমন mutex বা semaphore) ব্যবহার করতে হয়। এই লক-আনলক প্রক্রিয়া কনকারেন্সি এবং প্যারাল্যালিযম উভয় ক্ষেত্রেই ওভারহেড তৈরি করে। কনকারেন্সির ক্ষেত্রে, যেখানে একাধিক টাস্ক একসঙ্গে ম্যানেজ করা হয়, লকিংয়ের কারণে একটি থ্রেড অন্যটির জন্য অপেক্ষা করতে পারে। আবার প্যারাল্যালিযম, যেখানে একাধিক থ্রেড ভিন্ন ভিন্ন CPU কোরে একসঙ্গে চলে, লকিং শেয়ার্ড রিসোর্সের জন্য কনটেনশন সৃষ্টি করে, যা পারফরম্যান্সে বাধা দেয়। ফলে দেখা যায়, শেয়ার্ড মেমোরি এবং লকিং থিওরি প্যারালাল প্রোগ্রামিংয়ের সম্পূর্ণ সুবিধা গ্রহণে প্রতিবন্ধকতা তৈরি করে।

কনকারেন্সি (concurrency) এবং প্যারাল্যালিযম (parallelism) আলাদা ধারণা। কনকারেন্সি মানে একাধিক টাস্ক একসাথে ম্যানেজ করা, যেখানে প্যারাল্যালিযম মানে একই সময়ে একাধিক টাস্ক ফিজিক্যালি এক্সিকিউট করা।

এবার যদি আমরা অপরেটিং সিস্টেমের (OS) প্রেক্ষাপটে চিন্তা করি, ধরা যাক আমরা একসঙ্গে ১০টি আলাদা প্রোগ্রাম (প্রসেস) চালাতে চাই। এ ক্ষেত্রে OS প্রতিটি প্রসেসের জন্য একটি স্বতন্ত্র ভার্চুয়াল মেমোরি স্পেস বরাদ্দ করে। প্রোগ্রামের ধরনের উপর নির্ভর করে এই মেমোরি বরাদ্দ সাধারণত কয়েক মেগাবাইট থেকে শুরু হয়, উদাহরণস্বরূপ, একটি ছোট C প্রোগ্রামের জন্য ১-২ MB এবং একটি বড় Python অ্যাপ্লিকেশনের জন্য ৮ MB বা তার বেশি। তবে ১০টি প্রসেস কনকারেন্টলি চালানোর সময়, যদি CPU কোরের সংখ্যা সীমিত থাকে (যেমন ৪টি কোর), তাহলে OS-কে বারবার কনটেক্সট সুইচিং করতে হবে। এই কনটেক্সট সুইচিং — যেখানে CPU রেজিস্টার, মেমোরি টেবিল এবং ক্যাশে আপডেট করা হয় — ভালোই ব্যয়বহুল। ফলে, প্রতিটি প্রসেসের এক্সিকিউশন সময় বাড়ে এবং সিস্টেমের সামগ্রিক পারফরম্যান্স কমে যায়।

তাহলে আমাদের মূল প্রশ্ন আসলে Go আসলে কনকারেন্সি কিভাবে হ্যান্ডেল করছে? কিভাবে গো এর কনকারেন্সি ফাস্ট এবং কনটেক্সট সুইচিং তূলনামূলক মেমেোরী কম লাগে? আমরা ধাপে ধাপে এগুলো বোঝার চেষ্টা করবো

পর্ব ১ CSP

CSP (Communicating Sequential Processes) হলো একটি তাত্ত্বিক ফ্রেমওয়ার্ক বা মডেল, যা কনকারেন্ট সিস্টেম ডিজাইন এবং বিশ্লেষণের জন্য ব্যবহৃত হয়। এটি ১৯৭৮ সালে স্যার টনি হোয়ার (C. A. R. Hoare) প্রথম প্রস্তাব করেন। CSP-এর মূল উদ্দেশ্য হলো কনকারেন্ট প্রসেসগুলোর মধ্যে যোগাযোগ এবং সিঙ্ক্রোনাইজেশনকে গাণিতিকভাবে মডেল করা, যাতে সিস্টেমের আচরণ নির্ভুলভাবে বোঝা যায়। এটি প্রোগ্রামিং ল্যাঙ্গুয়েজ, টুলস এবং অ্যালগরিদম ডিজাইনেও প্রভাব ফেলেছে (যেমন Go এর চ্যানেল)।

CSP আসলে কী?

CSP হলো এমন একটি ফর্মাল মডেল, যেখানে:

প্রসেস (Processes): সিস্টেমের মধ্যে স্বাধীনভাবে চলমান ইউনিট, যারা নিজেদের কাজ Sequential (ধারাবাহিকভাবে) ভাবে করে।

কমিউনিকেশন (Communication): প্রসেসগুলো একে অপরের সঙ্গে শুধুমাত্র মেসেজ পাসিং এর মাধ্যমে যোগাযোগ করে, শেয়ার্ড মেমোরি ব্যবহার না করে।

সিঙ্ক্রোনাইজেশন: যোগাযোগ সিঙ্ক্রোনাস, অর্থাৎ একটি প্রসেস মেসেজ পাঠাতে চাইলে অন্য প্রসেসকে সেই মেসেজ গ্রহণের জন্য প্রস্তুত থাকতে হবে।

CSP-এর মূল ধারণা হলো কনকারেন্ট সিস্টেমকে এমনভাবে ডিজাইন করা যাতে ডেটা রেস, ডেডলক বা অন্যান্য জটিলতা এড়ানো যায়।

পর্ব ২ গোরুটিন

Go-এর goroutines হলো ইউজার-স্পেসে চলে এবং OS কার্নেলের পরিবর্তে Go রানটাইম দ্বারা ম্যানেজ করা হয়। Go ভাষার দুটি প্রধান ফেজ আছে: কম্পাইল টাইম (যেখানে কোড মেশিন কোডে রূপান্তরিত হয়) এবং রানটাইম (যেখানে goroutines চালানো হয়)।

Goroutines-এর CPU ওভারহেড OS থ্রেডের তুলনায় অনেক কম, কারণ এগুলো তৈরি ও ম্যানেজ করতে খুবই কম রিসোর্স লাগে। Goroutines OS থ্রেডের তুলনায় অনেক হালকা। একটি goroutine-এর প্রাথমিক স্ট্যাক সাইজ মাত্র ২ কিলোবাইট, যা প্রয়োজন অনুযায়ী ডায়নামিকভাবে বাড়তে পারে, যেখানে OS থ্রেডের স্ট্যাক সাধারণত ১-৮ মেগাবাইট হয়। একাধিক goroutine একই প্রসেসের মধ্যে চলে এবং একই মেমোরি স্পেস শেয়ার করতে পারে, তবে শেয়ার্ড ডেটা অ্যাক্সেসের জন্য সিঙ্ক্রোনাইজেশন (যেমন চ্যানেল) প্রয়োজন।

Goroutines-এর কনটেক্সট সুইচিং OS থ্রেডের তুলনায় অনেক কম ব্যয়বহুল। OS থ্রেডে কার্নেল-লেভেল সুইচিং লাগে, যা সময়সাপেক্ষ, কিন্তু Go রানটাইম goroutines-এর কনটেক্সট সুইচিং ইউজার-স্পেসে দ্রুততার সঙ্গে করে। ফলে, হাজার হাজার goroutine একসঙ্গে চালানো সম্ভব, যা OS থ্রেড দিয়ে অর্জন করা অত্যন্ত কঠিন।

Goroutines in Go run in the context of OS threads

ধরি, বাংলাদেশের ফিল্ম ইন্ডাস্ট্রিতে একটা বিরাট “নায়ক-নায়িকা নির্বাচন” হচ্ছে। ১০০ জন স্টার (goroutines) লাইন দিয়েছে, সবাই চায় “সেরা নায়ক” বা “সেরা নায়িকা” হতে। কেউ এন্ট্রি দিচ্ছে, কেউ ড্যান্স করছে, কেউ ডায়লগ মারছে। কিন্তু জাজদের কাছে মাত্র ৪টা মাইক্রোফোন (OS threads) আছে, যেগুলো দিয়ে প্রতিযোগীরা পারফর্ম করবে। আপনি হলেই প্রোডিউসার (Go runtime), আর আপনার সহকারী হলো “জাজপ্যানেলের জগলু” (Go Scheduler)।

১০০ জন স্টার (Goroutines): এরা হলো নায়ক-নায়িকার প্রতিযোগী। শাকিব খান বলছে “আমি হিরো!”, বুবলি ড্যান্স করে “আমি নাম্বার ওয়ান!”, পূর্ণিমা ডায়লগ মারছে “তোমার চোখে ডুবে যাই!”, আর ফেরদৌস চিৎকার করছে “আমি ফিরে আসবো!”। এদের জন্য খুব কম জায়গা লাগে (২ কিলোবাইট স্ট্যাক), তাই ১০০ জনই একসঙ্গে লাইনে দাঁড়াতে পারে।

৪টা মাইক্রোফোন (OS Threads): এগুলোই আসল “পারফর্ম করার মেশিন”। জাজরা (operating system) বলে দিয়েছে, “৪টার বেশি মাইক দিচ্ছি না, বাজেট কম!”। মাইকগুলো বড় আর ভারী (১-৮ মেগাবাইট), তাই বেশি পাওয়া যায় না।

আপনি, প্রোডিউসার (Go Runtime): আপনি পুরো নির্বাচনের বস। “শুরু করো! থামো! পরের জন!” — সব আপনি ঠিক করছেন।

জগলু (Go Scheduler): আপনার হেলপার। মাথায় টুপি, হাতে লিস্ট নিয়ে ঘুরছে, ঠিক করছে কে কখন মাইক পাবে।

নির্বাচন কীভাবে চলে?

শুরু: আপনি আর জগলু মিলে ৪ জনকে মাইক দিলেন। শাকিব মাইক নিয়ে চিৎকার করল, “আমি সেরা নায়ক, ভোট দাও!”। বুবলি ড্যান্স করল, “আমি সেরা নায়িকা!”। ফেরদৌস ডায়লগ মারল, “আমার ফ্যানরা আমাকে চায়!”। পূর্ণিমা গান গাইল, “তোমার হৃদয়ে আমি!”।

চা-ঝামেলা: শাকিব হঠাৎ থেমে বলল, “আমার চা লাগবে, গলা শুকিয়ে গেছে!” (I/O ব্লকড)। জগলু হেসে মাইক কেড়ে নিয়ে বলল, “তুই চা খা, আমি এই মাইকটা জায়েদ খানকে দিচ্ছি — ‘আমি রাজা, ভোট আমার!’ বল!”।

ড্যান্স ফ্লপ: বুবলি ড্যান্স করতে করতে হোঁচট খেয়ে পড়ে গেল (CPU task শেষ)। জগলু দৌড়ে গিয়ে বলল, “আরে, তুই উঠে পড়, আমি এই মাইকটা সাইমনকে দিচ্ছি — ‘আমি নতুন হিরো, আমাকে ভোট দাও!’ বল!”।

মাইকের লড়াই: শাকিব আর জায়েদ একটা মাইক নিয়ে ঝগড়া শুরু করল (race condition)। জগলু চিৎকার করে বলল, “একজন একজন করে! শাকিব, তুই আগে ‘হিরো ৪২০’ বল, তারপর জায়েদ ‘আমি রাজা’!”।

ফানি টুইস্ট: ফেরদৌস ডায়লগ মারতে মারতে হাঁপিয়ে গেল। জগলু হাসতে হাসতে বলল, “তুই গলায় পানি ঢাল, আমি এই মাইকটা নুসরাত ফারিয়াকে দিচ্ছি — ‘আমি সেরা নায়িকা, ভোট দাও!’ বল!”।

কী হলো?

প্রতিযোগীরা (goroutines) পারফর্ম করতে পারে শুধু মাইক (OS threads) পেলে। তাই এরা মাইকের “প্রেক্ষাপটে” বা “context-এ” চিৎকার করছে।

আপনি (Go runtime) আর জগলু (Go scheduler) মিলে ৪টা মাইক দিয়েই ১০০ জন স্টারের “ভোট দাও!” কম্পিটিশন চালিয়ে দিচ্ছো। কেউ থামলে, হোঁচট খেলে, বা চা খেতে গেলে জগলু হাসতে হাসতে মাইক অন্যজনের হাতে তুলে দিচ্ছে। জাজদের (OS) কাছে গিয়ে বাড়তি মাইক চাইতে হচ্ছে না, তবু নির্বাচন ফাটাফাটি চলছে!

পরের পর্বে Go Scheduler কিভাবে প্রসেসর এর সাথে কাজ করে, কিভাবে প্রোগ্রামগুলোকে কনকারেন্টিলি হ্যান্ডেল করে এগুলো নিয়ে আলোচনা করবো।

আসলে আমার লক্ষ্য বিহাইন্ড দ্যা সিনে গো কনকারেন্সি কিভাবে কাজ করে, কিভাবে ওএস থ্রেড এগুলোকে সামলায় এগুলোকে আমার সাধ্য অনুযায়ী বোঝানোর চেষ্টা করছি।

একটা গো কোড যখন চলে তখন রানটাইমে কি কি ঘটে তার একটা ভালো আইডিয়া পাবেন এইখানে। হাবিব ভাই খুবই ভালোভাবে এক্সপ্লেইন করেছেন


পরবর্তী পর্বে আবার দেখা হবে, আপনারা সবাই সেই পর্যন্ত অনেক অনেক ভালো থাকুন।

Comments