रूबी में धागा क्या है?
थ्रेड आपके रूबी प्रोग्राम को एक ही समय में कई काम करते हैं।
जैसी चीजें :
- एकाधिक फ़ाइलें पढ़ना
- एकाधिक वेब अनुरोध को संभालना
- एकाधिक API कनेक्शन बनाना
थ्रेड्स का उपयोग करने के परिणामस्वरूप, आपके पास एक बहु-थ्रेडेड रूबी प्रोग्राम होगा, जो चीजों को तेजी से पूरा करने में सक्षम है।
लेकिन एक चेतावनी…
MRI (Matz's Ruby Interpreter) में, रूबी अनुप्रयोगों को चलाने का डिफ़ॉल्ट तरीका, आपको केवल i/o बाउंड एप्लिकेशन चलाते समय थ्रेड्स से लाभ होगा। ।
GIL (ग्लोबल इंटरप्रेटर लॉक) . के कारण यह सीमा मौजूद है ।
वैकल्पिक रूबी दुभाषिए जैसे JRuby या Rubinius मल्टी-थ्रेडिंग का पूरा फायदा उठाते हैं।
तो, धागे क्या हैं?
धागे श्रमिक हैं, या निष्पादन की इकाइयाँ हैं।
प्रत्येक प्रक्रिया में कम से कम एक धागा होता है और आप मांग पर अधिक बना सकते हैं।
मुझे पता है कि आप एक कोड उदाहरण देखना चाहते हैं।
लेकिन सबसे पहले, हमें CPU बाउंड और I/O बाउंड एप्लिकेशन के बीच अंतर के बारे में बात करने की आवश्यकता है।
I/O बाउंड एप्लिकेशन
एक i/o बाउंड ऐप वह है जिसे बाहरी संसाधन की प्रतीक्षा करने की आवश्यकता है:
- एपीआई अनुरोध
- डेटाबेस (क्वेरी परिणाम)
- डिस्क रीड
संसाधन उपलब्ध होने की प्रतीक्षा करते समय एक थ्रेड रुकने का निर्णय ले सकता है। इसका मतलब है कि एक और धागा चल सकता है और अपना काम कर सकता है और प्रतीक्षा में समय बर्बाद नहीं कर सकता।
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
ठीक है, उम्मीद है कि आपने रूबी थ्रेड्स . के बारे में एक या दो बातें सीखी हैं !
अगर आपको यह लेख उपयोगी लगा हो तो कृपया इसे शेयर करें अपने दोस्तों के साथ ताकि वे भी सीख सकें 🙂