রুবি একটি থ্রেড কি?
থ্রেডগুলি আপনার রুবি প্রোগ্রামগুলিকে একই সময়ে একাধিক জিনিস করতে বাধ্য করে৷
যেমন জিনিসগুলি৷ :
- একাধিক ফাইল পড়া
- একাধিক ওয়েব অনুরোধ পরিচালনা করা
- একাধিক API সংযোগ তৈরি করা
থ্রেড ব্যবহার করার ফলে, আপনার কাছে একটি মাল্টি-থ্রেডেড রুবি প্রোগ্রাম থাকবে, যা কাজগুলি দ্রুত সম্পন্ন করতে সক্ষম।
কিন্তু একটি সতর্কতা...
MRI (Matz’s Ruby Interpreter), রুবি অ্যাপ্লিকেশন চালানোর ডিফল্ট উপায়, আপনি i/o আবদ্ধ অ্যাপ্লিকেশন চালানোর সময় শুধুমাত্র থ্রেড থেকে উপকৃত হবেন। .
GIL (গ্লোবাল ইন্টারপ্রেটার লক) এর কারণে এই সীমাবদ্ধতা বিদ্যমান .
JRuby বা Rubinius-এর মত বিকল্প রুবি দোভাষী মাল্টি-থ্রেডিংয়ের সম্পূর্ণ সুবিধা নেয়।
তাহলে, থ্রেড কি?
থ্রেড হল শ্রমিক, বা মৃত্যুদন্ডের একক।
প্রতিটি প্রক্রিয়ার অন্তত একটি থ্রেড থাকে এবং আপনি চাহিদা অনুযায়ী আরও তৈরি করতে পারেন।
আমি জানি আপনি একটি কোড উদাহরণ দেখতে চান৷
৷কিন্তু প্রথমে, আমাদের CPU আবদ্ধ এবং I/O আবদ্ধ অ্যাপ্লিকেশনের মধ্যে পার্থক্য সম্পর্কে কথা বলতে হবে।
I/O আবদ্ধ অ্যাপ্লিকেশনগুলি
একটি i/o আবদ্ধ অ্যাপ ৷ একটি বাহ্যিক সম্পদের জন্য অপেক্ষা করতে হবে:
- একটি API অনুরোধ
- ডাটাবেস (কোয়েরি ফলাফল)
- একটি ডিস্ক রিড
একটি থ্রেড একটি সংস্থান উপলব্ধ হওয়ার জন্য অপেক্ষা করার সময় থামার সিদ্ধান্ত নিতে পারে। এর মানে হল যে অন্য থ্রেড চলতে পারে এবং তার কাজটি করতে পারে এবং অপেক্ষায় সময় নষ্ট করতে পারে না।
একটি i/o আবদ্ধ অ্যাপের একটি উদাহরণ একটি ওয়েব ক্রলার।
প্রতিটি অনুরোধের জন্য, ক্রলারকে সার্ভারের প্রতিক্রিয়ার জন্য অপেক্ষা করতে হবে এবং অপেক্ষা করার সময় এটি কিছু করতে পারে না।
কিন্তু আপনি যদি থ্রেড ব্যবহার করেন…
আপনি একবারে 4টি অনুরোধ করতে পারেন এবং প্রতিক্রিয়াগুলি ফিরে আসার সাথে সাথে পরিচালনা করতে পারেন, যা আপনাকে দ্রুত পৃষ্ঠাগুলি আনতে দেয়৷
এখন আপনার কোড উদাহরণের সময়।
রুবি থ্রেড তৈরি করা
আপনি Thread.new
কল করে একটি নতুন রুবি থ্রেড তৈরি করতে পারেন .
এই থ্রেডটি চালানোর জন্য যে কোডটি প্রয়োজন তা সহ একটি ব্লকে পাস করা নিশ্চিত করুন৷
Thread.new { puts "hello from thread" }
বেশ সহজ, তাই না?
যাইহোক।
আপনার কাছে নিম্নলিখিত কোড থাকলে আপনি লক্ষ্য করবেন যে থ্রেড থেকে কোন আউটপুট নেই:
t = Thread.new { puts 10**10 } puts "hello"
সমস্যা হল রুবি থ্রেড শেষ হওয়ার জন্য অপেক্ষা করে না।
আপনাকে join
কল করতে হবে উপরের কোডটি ঠিক করার জন্য আপনার থ্রেডে পদ্ধতি:
t = Thread.new { puts 10**10 } puts "hello" t.join
আপনি যদি একাধিক থ্রেড তৈরি করতে চান তবে আপনি সেগুলিকে একটি অ্যারের মধ্যে রাখতে পারেন এবং join
কল করতে পারেন প্রতিটি থ্রেডে।
উদাহরণ :
threads = [] 10.times { threads << Thread.new { puts 1 } } threads.each(&:join)
আপনার রুবি থ্রেড অন্বেষণের সময় আপনি ডকুমেন্টেশন দরকারী খুঁজে পেতে পারেন:
https://ruby-doc.org/core-2.5.0/Thread.html
থ্রেড এবং ব্যতিক্রম
যদি একটি থ্রেডের মধ্যে একটি ব্যতিক্রম ঘটে তবে এটি আপনার প্রোগ্রাম বন্ধ না করে বা কোনো ধরনের ত্রুটি বার্তা না দেখিয়ে চুপচাপ মারা যাবে৷
এখানে একটি উদাহরণ:
Thread.new { raise 'hell' }
ডিবাগিং উদ্দেশ্যে, আপনি খারাপ কিছু ঘটলে আপনার প্রোগ্রাম বন্ধ করতে চাইতে পারেন। এটি করতে আপনি Thread
-এ নিম্নলিখিত পতাকা সেট করতে পারেন সত্য থেকে:
Thread.abort_on_exception = true
আপনি আপনার থ্রেড তৈরি করার আগে এই পতাকা সেট করতে ভুলবেন না 🙂
থ্রেড পুল
ধরুন আপনার কাছে প্রক্রিয়া করার জন্য শত শত আইটেম আছে, সেগুলির প্রতিটির জন্য একটি থ্রেড শুরু করা আপনার সিস্টেম সংস্থানগুলিকে ধ্বংস করে দেবে৷
এটি দেখতে এরকম কিছু হবে:
pages_to_crawl = %w( index about contact ... ) pages_to_crawl.each do |page| Thread.new { puts page } endরাখে
আপনি যদি এটি করেন তবে আপনি সার্ভারের বিরুদ্ধে শত শত সংযোগ চালু করবেন, তাই সম্ভবত এটি একটি ভাল ধারণা নয়৷
একটি সমাধান হল একটি থ্রেড পুল ব্যবহার করা।
থ্রেড পুল আপনাকে যে কোনো সময়ে সক্রিয় থ্রেডের সংখ্যা নিয়ন্ত্রণ করতে দেয়।
আপনি নিজের পুল তৈরি করতে পারেন, কিন্তু আমি এটি সুপারিশ করব না। নিম্নলিখিত উদাহরণে আমরা আপনার জন্য এটি করতে সেলুলয়েড মণি ব্যবহার করছি৷
দ্রষ্টব্য:সেলুলয়েড এখন অপরিবর্তিত, কিন্তু কর্মী পুলের সাধারণ ধারণা এখনও প্রযোজ্য৷
require 'celluloid' class Worker include Celluloid def process_page(url) puts url end end pages_to_crawl = %w( index about contact products ... ) worker_pool = Worker.pool(size: 5) # If you need to collect the return values check out 'futures' pages_to_crawl.each do |page| worker_pool.process_page(page) end
এইবার মাত্র 5টি থ্রেড চলবে, এবং সেগুলি শেষ হওয়ার সাথে সাথে তারা পরবর্তী আইটেমটি বেছে নেবে৷
জাতির অবস্থা এবং অন্যান্য বিপদ
এটি খুব সুন্দর শোনাতে পারে তবে আপনি আপনার কোড জুড়ে থ্রেড ছিটিয়ে যাওয়ার আগে আপনাকে অবশ্যই জানতে হবে যে সমবর্তী কোডের সাথে কিছু সমস্যা রয়েছে।
উদাহরণস্বরূপ, থ্রেডগুলি জাতিগত অবস্থার জন্য প্রবণ।
একটি জাতি শর্ত যখন জিনিসগুলি শৃঙ্খলার বাইরে ঘটে এবং তালগোল পাকিয়ে দেয়৷
আরেকটি সমস্যা যা ঘটতে পারে তা হল একটি অচলাবস্থা। এটি তখন হয় যখন একটি থ্রেড কোনো রিসোর্সে এক্সক্লুসিভ অ্যাক্সেস (মিউটেক্সের মতো একটি লকিং সিস্টেম ব্যবহার করে) ধারণ করে এবং এটি কখনই প্রকাশ করে না, যা এটিকে অন্য সব থ্রেডে অ্যাক্সেসযোগ্য করে তোলে।
এই সমস্যাগুলি এড়াতে, কাঁচা থ্রেড এড়িয়ে চলা এবং এমন কিছু রত্নের সাথে লেগে থাকা ভাল যা ইতিমধ্যে আপনার জন্য বিশদ বিবরণের যত্ন নেয়৷
আরো থ্রেডিং রত্ন
আমরা ইতিমধ্যেই আমাদের থ্রেড পুলের জন্য সেলুলয়েড ব্যবহার করেছি, তবে আরও অনেকগুলি সঙ্গতি-কেন্দ্রিক রত্ন রয়েছে যা আপনার পরীক্ষা করা উচিত:
- https://github.com/grosser/parallel
- https://github.com/chadrem/workers
- https://github.com/ruby-concurrency/concurrent-ruby
ঠিক আছে, আশা করি আপনি রুবি থ্রেড সম্পর্কে একটি বা দুটি জিনিস শিখেছেন !
আপনি যদি এই নিবন্ধটি দরকারী বলে মনে করেন তবে দয়া করে এটি ভাগ করুন৷ আপনার বন্ধুদের সাথে যাতে তারাও শিখতে পারে 🙂