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 पर उपलब्ध है, इसलिए आप स्वयं इसका प्रयोग कर सकते हैं।

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

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

थ्रेड

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

<img src="/images/blog/2017-04/threads.png">

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

mutex = Mutex.new
messages = []

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

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

loop do
  Thread.new(server.accept) do |socket|
    nickname = read_line_from(socket)
 
    # Send incoming message (coming up)
 
    # Read incoming messages (coming up)
  end
end

म्यूटेक्स

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

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

# Read incoming messages
while incoming = read_line_from(socket)
  mutex.synchronize do
    messages.push(
      :time => Time.now,
      :nickname => nickname,
      :text => incoming
    )
  end
end

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

# Send incoming message
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) के कारण रूबी "असली" थ्रेडिंग नहीं कर सकती है। यह आंशिक रूप से सच है। जीआईएल सभी रूबी कोड के निष्पादन के चारों ओर एक ताला है और रूबी प्रक्रिया को एक साथ कई सीपीयू का उपयोग करने से रोकता है। IO संचालन (जैसे कि इस लेख में हमारे द्वारा उपयोग किए गए नेटवर्क कनेक्शन) GIL के बाहर संचालित होते हैं, जिसका अर्थ है कि आप वास्तव में इस मामले में अच्छी संगति प्राप्त कर सकते हैं।

समाप्त हो रहा है

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

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


  1. आप रेल डीप डाइव कैसे करते हैं?

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

  1. रेल डीप डाइव कब लें

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

  1. भवन में एक गहरा गोता मारियो पेशेव के साथ 50+ व्यक्ति वर्डप्रेस स्टूडियो

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