Ruby Language
पंक्ति
खोज…
वाक्य - विन्यास
- क्यू = क्यू। न्यू
- q.push वस्तु
- q << ऑब्जेक्ट # समान # पश के रूप में
- q.pop # => वस्तु
मल्टीपल वर्कर्स वन सिंक
हम कई वर्कर्स द्वारा बनाए गए डेटा को इकट्ठा करना चाहते हैं।
सबसे पहले हम एक कतार बनाते हैं:
sink = Queue.new
फिर 16 श्रमिक सभी एक यादृच्छिक संख्या उत्पन्न करते हैं और इसे सिंक में धकेलते हैं:
(1..16).to_a.map do
Thread.new do
sink << rand(1..100)
end
end.map(&:join)
और डेटा प्राप्त करने के लिए, एक कतार को एक सरणी में परिवर्तित करें:
data = [].tap { |a| a << sink.pop until sink.empty? }
वन सोर्स मल्टीपल वर्कर्स
हम डेटा को समानांतर में प्रोसेस करना चाहते हैं।
चलो कुछ डेटा के साथ स्रोत आबाद करें:
source = Queue.new
data = (1..100)
data.each { |e| source << e }
फिर डेटा को संसाधित करने के लिए कुछ कार्यकर्ता बनाएं:
(1..16).to_a.map do
Thread.new do
until source.empty?
item = source.pop
sleep 0.5
puts "Processed: #{item}"
end
end
end.map(&:join)
एक स्रोत - कार्य की पाइपलाइन - एक सिंक
हम डेटा को समानांतर में संसाधित करना चाहते हैं और इसे अन्य श्रमिकों द्वारा संसाधित की जाने वाली रेखा के नीचे धकेल देते हैं।
चूंकि श्रमिक दोनों डेटा का उपभोग करते हैं और हमें दो कतारें बनानी होती हैं:
first_input_source = Queue.new
first_output_sink = Queue.new
100.times { |i| first_input_source << i }
श्रमिकों की पहली लहर first_input_source
से एक आइटम first_input_source
, आइटम संसाधित करती है, और first_output_sink
में परिणाम first_output_sink
:
(1..16).to_a.map do
Thread.new do
loop do
item = first_input_source.pop
first_output_source << item ** 2
first_output_source << item ** 3
end
end
end
श्रमिकों की दूसरी लहर अपने इनपुट स्रोत के रूप में first_output_sink
का उपयोग first_output_sink
और फिर दूसरी आउटपुट सिंक पर प्रक्रिया को पढ़ती है:
second_input_source = first_output_sink
second_output_sink = Queue.new
(1..32).to_a.map do
Thread.new do
loop do
item = second_input_source.pop
second_output_sink << item * 2
second_output_sink << item * 3
end
end
end
अब second_output_sink
सिंक सिंक है, आइए इसे एक सरणी में second_output_sink
:
sleep 5 # workaround in place of synchronization
sink = second_output_sink
[].tap { |a| a << sink.pop until sink.empty? }
एक कतार में डेटा धक्का - #push
q = Queue.new
q << "any object including another queue"
# or
q.push :data
- कोई उच्च पानी का निशान नहीं है, कतारें अनंत रूप से बढ़ सकती हैं।
-
#push
कभी ब्लॉक नहीं होता
एक कतार से डेटा खींचना - #pop
q = Queue.new
q << :data
q.pop #=> :data
-
#pop
तब तक ब्लॉक रहेगा जब तक कि कुछ डेटा उपलब्ध नहीं है। -
#pop
को सिंक्रोनाइज़ेशन के लिए इस्तेमाल किया जा सकता है।
तुल्यकालन - समय में एक बिंदु के बाद
syncer = Queue.new
a = Thread.new do
syncer.pop
puts "this happens at end"
end
b = Thread.new do
puts "this happens first"
STDOUT.flush
syncer << :ok
end
[a, b].map(&:join)
एक पंक्ति को एक सरणी में परिवर्तित करना
q = Queue.new
q << 1
q << 2
a = Array.new
a << q.pop until q.empty?
या एक लाइनर :
[].tap { |array| array < queue.pop until queue.empty? }
दो कतारें मिलाना
- असीम रूप से अवरुद्ध होने से बचने के लिए, कतारों से पढ़ना थ्रेड मर्ज पर नहीं होना चाहिए।
- तुल्यकालन से बचने के लिए या असीम रूप से एक कतार का इंतजार करते हुए, जबकि अन्य में डेटा होता है, कतारों से पढ़ना एक ही धागे पर नहीं होना चाहिए।
चलो दो कतारों को परिभाषित और आबाद करके शुरू करते हैं:
q1 = Queue.new
q2 = Queue.new
(1..100).each { |e| q1 << e }
(101..200).each { |e| q2 << e }
हमें एक और कतार बनाना चाहिए और इसमें अन्य थ्रेड्स से डेटा पुश करना चाहिए:
merged = Queue.new
[q1, q2].map do |q|
Thread.new do
loop do
merged << q.pop
end
end
end
यदि आप जानते हैं कि आप पूरी तरह से दोनों कतारों का उपभोग कर सकते हैं (खपत की गति उत्पादन से अधिक है, तो आप रैम से बाहर नहीं निकलेंगे) एक सरल तरीका है:
merged = Queue.new
merged << q1.pop until q1.empty?
merged << q2.pop until q2.empty?