Multithreading হলো এমন একটি কৌশল, যেখানে একসাথে একাধিক থ্রেড চলতে পারে, ফলে একই প্রোগ্রামের মধ্যে বিভিন্ন কাজ একসাথে (parallel) বা আলাদা আলাদা সময় (concurrent) এ সম্পন্ন হতে পারে। রুবি ভাষায় multithreading ব্যবহার করে আপনি একাধিক থ্রেডের মাধ্যমে ডেটা প্রসেসিং, I/O অপারেশন, বা লম্বা সময়ের কাজ গুলি দ্রুত সম্পন্ন করতে পারেন।
রুবি থ্রেডিং ম্যানেজমেন্ট Thread ক্লাসের মাধ্যমে করা হয়, যা রুবির একটি গুরুত্বপূর্ণ কম্পোনেন্ট। এটি আপনাকে একাধিক থ্রেড তৈরি, থ্রেডগুলোর মধ্যে সমন্বয় এবং থ্রেডগুলির মধ্যে ডেটা শেয়ার করার সুযোগ দেয়।
১. Thread ক্লাসের মাধ্যমে Multithreading
রুবিতে Thread ক্লাস ব্যবহার করে নতুন থ্রেড তৈরি এবং পরিচালনা করা হয়। এটি থ্রেডের মধ্যে কোড এক্সিকিউট করে এবং Thread.new ব্যবহার করে নতুন থ্রেড শুরু করা হয়।
Thread.new Syntax:
thread = Thread.new do
# কাজ যা থ্রেডে চলবে
endএকটি সাধারণ উদাহরণ:
# একটি থ্রেড তৈরি করা হচ্ছে
thread = Thread.new do
5.times do |i|
puts "Thread 1: #{i}"
sleep(1) # 1 সেকেন্ডের জন্য থ্রেডটি অপেক্ষা করবে
end
end
# মেইন থ্রেডে আরেকটি কাজ
5.times do |i|
puts "Main thread: #{i}"
sleep(1) # 1 সেকেন্ডের জন্য থ্রেডটি অপেক্ষা করবে
end
# থ্রেডটি শেষ হওয়া পর্যন্ত অপেক্ষা করা
thread.joinআউটপুট:
Main thread: 0
Thread 1: 0
Main thread: 1
Thread 1: 1
Main thread: 2
Thread 1: 2
Main thread: 3
Thread 1: 3
Main thread: 4
Thread 1: 4এখানে, একটি নতুন থ্রেড তৈরি করা হয়েছে, যা ৫টি বার "Thread 1: X" মুদ্রণ করবে, এবং মেইন থ্রেডে অন্য একটি কাজ চলছে যা "Main thread: X" মুদ্রণ করবে। sleep(1) ব্যবহারের মাধ্যমে প্রতিটি থ্রেডে ১ সেকেন্ডের জন্য বিরতি দেওয়া হয়েছে।
২. Thread#join Method
join মেথড থ্রেডের কার্যক্রম সমাপ্ত হওয়ার জন্য অপেক্ষা করে। যদি আপনি চাইেন যে মেইন থ্রেড অন্য থ্রেডের কাজ শেষ না হওয়া পর্যন্ত অপেক্ষা করুক, তাহলে join ব্যবহার করতে হবে।
thread = Thread.new do
5.times do |i|
puts "Thread 1: #{i}"
sleep(1)
end
end
# মেইন থ্রেডে অন্য কাজ
puts "Main thread is waiting for Thread 1 to finish..."
thread.join # Thread 1 এর কাজ শেষ না হওয়া পর্যন্ত অপেক্ষা করা হবে
puts "Thread 1 has finished."এখানে, join মেথড ব্যবহার করে মেইন থ্রেড Thread 1 এর কাজ শেষ হওয়ার জন্য অপেক্ষা করছে।
৩. Thread Synchronization
একাধিক থ্রেড একসাথে কাজ করার সময় data consistency নিশ্চিত করার জন্য সিঙ্ক্রোনাইজেশন প্রয়োজন হয়। রুবি Mutex (Mutual Exclusion) ব্যবহার করে থ্রেডের মধ্যে সিঙ্ক্রোনাইজেশন নিশ্চিত করে।
Mutex Example:
mutex = Mutex.new
thread1 = Thread.new do
mutex.synchronize do
5.times do |i|
puts "Thread 1: #{i}"
sleep(1)
end
end
end
thread2 = Thread.new do
mutex.synchronize do
5.times do |i|
puts "Thread 2: #{i}"
sleep(1)
end
end
end
# থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করা
thread1.join
thread2.joinএখানে, mutex.synchronize ব্যবহার করে আমরা প্রতিটি থ্রেডের কাজ সিঙ্ক্রোনাইজ করেছি, যাতে একসাথে থ্রেডগুলো একই রিসোর্স একসাথে এক্সেস না করে।
৪. Thread Pooling (থ্রেড পুলিং)
একাধিক থ্রেড তৈরি করার সময় অনেক ক্ষেত্রে একই ধরনের কাজের জন্য থ্রেড পুনরায় ব্যবহার করা হতে পারে, যা Thread Pooling এর মাধ্যমে করা হয়। রুবিতে Concurrent::Future বা ThreadPool গেমপ্যাক ব্যবহার করে থ্রেড পুল তৈরি করা সম্ভব।
Thread Pool Example (Concurrent Gem):
# Concurrent gem ইনস্টল করা
# gem install concurrent-ruby
require 'concurrent-ruby'
pool = Concurrent::ThreadPoolExecutor.new
# থ্রেড পুলে কাজ যোগ করা
10.times do |i|
pool.post do
puts "Task #{i} is being executed"
sleep(1)
end
end
# সব কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করা
pool.shutdown
pool.wait_for_terminationএখানে, ThreadPoolExecutor ব্যবহার করে ১০টি টাস্ক পুলে যোগ করা হয়েছে এবং shutdown এর মাধ্যমে থ্রেড পুলটি বন্ধ হয়ে গেলে অপেক্ষা করা হচ্ছে।
৫. Thread Safety (থ্রেড সেফটি)
থ্রেড সেফটি নিশ্চিত করতে হলে আপনার কোড এমনভাবে লিখতে হবে যাতে একাধিক থ্রেড একসাথে একই রিসোর্স বা ডেটা পরিবর্তন করতে না পারে। এজন্য Mutex এবং Atomic Variables (যেমন Concurrent::Atomic) ব্যবহার করা যেতে পারে।
Thread Safety Example:
require 'concurrent-ruby'
counter = Concurrent::AtomicFixnum.new(0)
threads = []
5.times do
threads << Thread.new do
10.times do
counter.increment
end
end
end
threads.each(&:join)
puts "Final counter value: #{counter.value}"এখানে, Concurrent::AtomicFixnum ব্যবহার করে থ্রেড সেফভাবে একটি কাউন্টার ইনক্রিমেন্ট করা হয়েছে।
৬. থ্রেডের কিছু সীমাবদ্ধতা
রুবি তে থ্রেডিং ব্যবহারের সময় কিছু সীমাবদ্ধতা থাকে, যা মূলত Global Interpreter Lock (GIL) এর কারণে ঘটে। GIL হল একটি মেকানিজম যা একই সময়ে একাধিক থ্রেডকে সম্পূর্ণরূপে কার্যকরী হতে দেয় না, তবে এটি I/O অপারেশনগুলি (যেমন ফাইল বা নেটওয়ার্ক রিকোয়েস্ট) পরিচালনা করার জন্য কার্যকরী।
- CPU Bound Task: রুবিতে থ্রেডিং CPU-bound কাজগুলির জন্য খুব কার্যকরী নয়, কারণ GIL কেবল একটি থ্রেডকে একবারে CPU রিসোর্স দেওয়ার অনুমতি দেয়।
- I/O Bound Task: I/O অপারেশনের জন্য থ্রেডিং কার্যকরী, যেমন ওয়েব রিকোয়েস্ট, ফাইল রিড বা রাইট ইত্যাদি।
সারসংক্ষেপ
- Multithreading রুবিতে একাধিক থ্রেডের মাধ্যমে একযোগভাবে কাজ সম্পাদন করার জন্য ব্যবহৃত হয়।
- Thread ক্লাস দিয়ে নতুন থ্রেড তৈরি, এবং
Thread.newওThread#joinব্যবহার করে থ্রেডের কার্যক্রম নিয়ন্ত্রণ করা হয়। - Mutex ব্যবহার করে থ্রেড সিঙ্ক্রোনাইজেশন নিশ্চিত করা যায়।
- Thread Safety এবং Atomic Variables ব্যবহারের মাধ্যমে থ্রেড সেফটি নিশ্চিত করা সম্ভব।
- রুবিতে Global Interpreter Lock (GIL) এর কারণে CPU-bound কাজের ক্ষেত্রে থ্রেডিং সীমাবদ্ধ হতে পারে, তবে I/O-bound কাজের জন্য থ্রেডিং খুব কার্যকরী।
Read more