Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Ruby

रूबी कंकरेंसी में महारत: मल्टी-थ्रेडेड चैट सिस्टम बनाना

पिछले रूबी मैजिक संस्करण में हमने दिखाया कि आप कई प्रोसेस का उपयोग करके चैट सिस्टम कैसे लागू कर सकते हैं। इस बार हम आपको दिखाएंगे कि आप उसी चीज़ को कई थ्रेड का उपयोग करके कैसे कर सकते हैं।

त्वरित रिकैप

यदि आप बुनियादी सेटअप का पूरा स्पष्टीकरण चाहते हैं तो पिछले लेख को देखें। लेकिन आपको जल्दी याद दिलाने के लिए: यह है कि हमारा चैट सिस्टम कैसा दिखता है:

हम पहले उपयोग किए गए उसी क्लाइंट का उपयोग कर रहे हैं:

# client.rb
# $ ruby client.rb
require 'socket'
client = TCPSocket.open(ARGV[0], 2000)
Thread.new do
  while line = client.gets
    puts line.chop
  end
end
while input = STDIN.gets.chomp
  client.puts input
end

सर्वर के लिए बुनियादी सेटअप वही है:

# server_threads.rb
# $ ruby server_threads.rb
require 'socket'
puts 'Starting server on port 2000'
server = TCPServer.open(2000)

इस लेख में उदाहरणों में उपयोग किया गया पूरा सोर्स कोड GitHub पर उपलब्ध है, ताकि आप स्वयं इसके साथ प्रयोग कर सकें।

मल्टी-थ्रेडेड चैट सर्वर

अब हम उस भाग पर पहुंच रहे हैं जो मल्टी-प्रोसेस कार्यान्वयन की तुलना में अलग है। मल्टी-थ्रेडिंग का उपयोग करके हम केवल एक रूबी प्रोसेस के साथ एक ही समय में कई चीजें कर सकते हैं। हम इसे कई थ्रेड उत्पन्न करके करेंगे जो काम करते हैं।

थ्रेड

एक थ्रेड स्वतंत्र रूप से चलता है, एक प्रोसेस के भीतर कोड निष्पादित करता है। कई थ्रेड एक ही प्रोसेस में रह सकते हैं और वे मेमोरी साझा कर सकते हैं।

रूबी कंकरेंसी में महारत: मल्टी-थ्रेडेड चैट सिस्टम बनाना

आने वाले चैट संदेशों को संग्रहीत करने के लिए कुछ स्टोरेज की आवश्यकता होगी। हम एक सादा Array उपयोग करेंगे, लेकिन हमें यह सुनिश्चित करने के लिए एक Mutex की भी आवश्यकता है कि केवल एक थ्रेड एक ही समय में संदेशों को बदलता है (हम देखेंगे कि Mutex थोड़ी देर में कैसे काम करता है)।

mutex = Mutex.new
messages = []

अब हम एक लूप शुरू करते हैं जिसमें हम चैट क्लाइंट से आने वाले कनेक्शन स्वीकार करेंगे। एक बार कनेक्शन स्थापित हो जाने पर, हम उस क्लाइंट कनेक्शन से आने वाले और जाने वाले संदेशों को संभालने के लिए एक थ्रेड उत्पन्न करेंगे।

Thread.new कॉल तब तक ब्लॉक करता है जब तक server.accept कुछ लौटाता है, और फिर नए बनाए गए थ्रेड में निम्नलिखित ब्लॉक को यील्ड करता है। थ्रेड में कोड तब भेजी गई पहली लाइन को पढ़ता है और इसे निकनेम के रूप में संग्रहीत करता है। अंत में यह संदेश भेजना और पढ़ना शुरू करता है।

loop do
  Thread.new(server.accept) do |socket|
    nickname = read_line_from(socket)
    # आने वाला संदेश भेजें (आ रहा है)
    # आने वाले संदेश पढ़ें (आ रहा है)
  end
end

Mutex

म्यूटेक्स एक ऑब्जेक्ट है जो कई थ्रेड को यह समन्वय करने देता है कि वे साझा संसाधनों, जैसे सरणी, का उपयोग कैसे करते हैं। एक थ्रेड यह इंगित कर सकता है कि उसे एक्सेस की आवश्यकता है, और इस दौरान अन्य थ्रेड साझा संसाधन तक नहीं पहुंच सकते।

सर्वर सॉकेट से आने वाले संदेशों को पढ़ता है। यह synchronize का उपयोग करके संदेश स्टोर पर लॉक प्राप्त करता है, ताकि यह सुरक्षित रूप से Array में एक संदेश जोड़ सके।

# आने वाले संदेश पढ़ें
while incoming = read_line_from(socket)
  mutex.synchronize do
    messages.push(
      :time => Time.now,
      :nickname => nickname,
      :text => incoming
    )
  end
end

अंत में, एक Thread उत्पन्न होता है जो लूप में लगातार चलता है, यह सुनिश्चित करने के लिए कि सर्वर द्वारा प्राप्त सभी नए संदेश क्लाइंट को भेजे जा रहे हैं। फिर से यह लॉक प्राप्त करता है ताकि यह जान सके कि अन्य थ्रेड हस्तक्षेप नहीं कर रहे हैं। लूप के एक टिक के बाद यह थोड़ी देर सोता है और फिर जारी रहता है।

# आने वाला संदेश भेजें
Thread.new do
  sent_until = Time.now
  loop do
    messages_to_send = mutex.synchronize do
      get_messages_to_send(nickname, messages, sent_until).tap do
        sent_until = Time.now
      end
    end
    messages_to_send.each do |message|
      socket.puts "#{message[:nickname]}: #{message[:text]}"
    end
    sleep 0.2
  end
end

ग्लोबल इंटरप्रेटर लॉक

आपने शायद कहानी सुनी होगी कि रूबी रूबी के ग्लोबल इंटरप्रेटर लॉक (GIL) के कारण "असली" थ्रेडिंग नहीं कर सकता। यह आंशिक रूप से सच है। GIL सभी रूबी कोड के निष्पादन के चारों ओर एक लॉक है और रूबी प्रोसेस को कई CPU का समवर्ती उपयोग करने से रोकता है। IO ऑपरेशन (जैसे इस लेख में उपयोग किए गए नेटवर्क कनेक्शन) GIL के बाहर काम करते हैं, जिसका अर्थ है कि आप इस मामले में वास्तव में अच्छी समवर्ती प्राप्त कर सकते हैं।

निष्कर्ष

अब हमारे पास एक चैट सर्वर है जो एक थ्रेड प्रति कनेक्शन का उपयोग करके एक ही प्रोसेस के भीतर चल रहा है। यह मल्टी-प्रोसेस कार्यान्वयन की तुलना में बहुत कम संसाधनों का उपयोग करेगा। यदि आप कोड के विवरण देखना चाहते हैं या इसे आज़माना चाहते हैं तो आप उदाहरण कोड यहां पा सकते हैं।

इस श्रृंखला के अंतिम लेख में हम इसी चैट सर्वर को एक ही थ्रेड और इवेंट लूप का उपयोग करके लागू करेंगे। सैद्धांतिक रूप से यह थ्रेड कार्यान्वयन की तुलना में और भी कम संसाधनों का उपयोग करना चाहिए!

  1. - व्यापक Rails डीप डाइव कैसे संचालित करें

    शायद एक बग ठीक करने से दर्जनों नए बग पैदा हो गए। या आपका कोड इतने अजीब तरीके से टूटता है कि आप सोचते हैं कि क्या आप वास्तव में इसे समझते हैं। आपको लगता है कि डीप डाइव का समय आ गया है। लेकिन जानना कि आपको किसी विषय में गहराई से जाने की जरूरत है? वह केवल चरण 1 है। आप वास्तव में किसी विषय को उसके मूल स

  1. - Rails में डीप डाइव कब करें: अपनी महारत का समय तय करें

    क्या आपको कभी Rails का कोई विषय मिला है जिसका कोई मतलब नहीं था? जैसे, आपने सोचा कि आप इसे जानते हैं, इसलिए आपने कुछ कोड लिखा, और कुछ पूरी तरह से अलग हुआ? या आप जानते हैं कि आप समझते नहीं हैं, लेकिन आप बस इतना जानते हैं कि काम चल जाए, सिवाय इसके कि आप एज केसेज से लड़ने में इतना समय बिताते हैं कि जब त

  1. - 50-व्यक्ति वर्डप्रेस स्टूडियो का निर्माण: मारियो पेशेव से अंतर्दृष्टि

    उद्यमिता अपने जीवन के कुछ साल ऐसे जीना है जैसे ज्यादातर लोग नहीं जीते ताकि आप अपना बाकी जीवन ऐसे जी सकें जैसे ज्यादातर लोग नहीं जी सकते।   MalCare पर, हम वर्डप्रेस समुदाय में कई अलग-अलग तरीकों से योगदान देने पर ध्यान केंद्रित करते हैं। हम वर्डप्रेस उपयोगकर्ताओं के लिए वेब सुरक्षा के बारे मे