2010-06-17 13 views
10

मैं दो लिपियों जो मशीनीकरण का उपयोग एक गूगल सूचकांक पृष्ठ लाने में की है। मैंने माना कि EventMachine रूबी धागे से तेज होगा, लेकिन ऐसा नहीं है।इवेंटमैचिन का रूबी रूबी थ्रेड से धीमा क्यों है?

EventMachine कोड लागत: "0.24s user 0.08s system 2% cpu 12.682 total"

रूबी थ्रेड कोड लागत: "0.22s user 0.08s system 5% cpu 5.167 total "

मैं गलत तरीके से EventMachine का उपयोग कर रहा हूं?

EventMachine:

require 'rubygems' 
require 'mechanize' 
require 'eventmachine' 

trap("INT") {EM.stop} 

EM.run do 
    num = 0 
    operation = proc { 
    agent = Mechanize.new 
    sleep 1 
    agent.get("http://google.com").body.to_s.size 
    } 
    callback = proc { |result| 
    sleep 1 
    puts result 
    num+=1 
    EM.stop if num == 9 
    } 

    10.times do 
    EventMachine.defer operation, callback 
    end 
end 

रूबी थ्रेड:

require 'rubygems' 
require 'mechanize' 


threads = [] 
10.times do 
    threads << Thread.new do 
    agent = Mechanize.new 
    sleep 1 
    puts agent.get("http://google.com").body.to_s.size 
    sleep 1 
    end 
end 


threads.each do |aThread| 
    aThread.join 
end 
+0

रूबी का कौन सा संस्करण और कार्यान्वयन आप चल रहे हैं? जीआईएल (ग्लोबल दुभाषिया ताला) के साथ कार्यान्वयन के लिए, हरे धागे वास्तव में पूरी तरह से एक साथ नहीं चल सकते हैं। आप अपने देखे गए व्यवहार की पुष्टि करने के लिए jRuby या Rubinius में उदाहरण चलाने का प्रयास करना चाहेंगे –

उत्तर

9

हाँ, आप गलत यह प्रयोग कर रहे हैं। EventMachine एसिंक्रोनस आईओ कॉल करके काम करता है जो तुरंत लौटता है और "रिएक्टर" (ईएम.रुन द्वारा शुरू की गई घटना लूप) को पूरा होने पर सूचित करता है। आपके पास दो अवरुद्ध कॉल हैं जो सिस्टम, नींद और Mechanize.get के उद्देश्य को हराते हैं। EventMachine से किसी भी मूल्य को प्राप्त करने के लिए आपको विशेष एसिंक्रोनस/गैर-अवरुद्ध पुस्तकालयों का उपयोग करना होगा।

+2

आप सही हैं कि उन्होंने जो उदाहरण देखा है उसे एसिंक http लाइब्रेरी के साथ फिर से लिखा जा सकता है, लेकिन #defer विधि का बिंदु विशेष रूप से है ताकि आप स्पॉन कर सकें एक नया धागा जो रिएक्टर रन लूप को प्रभावित किए बिना अवरुद्ध करने वाला ऑपरेशन करता है। तो सैद्धांतिक रूप से, उनका उदाहरण रन लूप को अवरुद्ध नहीं कर रहा है। समय अंतर के साथ मेरा अनुमान यह है कि धागे निर्धारित कैसे होते हैं। –

+0

सामान्य इवेंटमैचिन में ठीक से काम करता है कि आपने कैसे कहा, लेकिन आपका उत्तर 'डिफर' कॉल के उपयोग पर लागू नहीं होता है। –

2

EventMachine की तरह कुछ का उपयोग करना चाहिए "स्थगित" वास्तव में एक ThreadPool यह आपके अनुरोध को पूरा करने का प्रबंधन करता है से रूबी धागे spawns। हाँ, EventMachine गैर अवरुद्ध आईओ के संचालन के लिए डिज़ाइन किया गया है, लेकिन आस्थगित करें आदेश एक अपवाद है - यह आप रिएक्टर को रोके बिना लंबी चलने वाली संचालन करने के लिए अनुमति देने के लिए बनाया गया है।

इसलिए, यह क्योंकि वास्तव में यह सिर्फ EventMachine के ThreadPool प्रबंधक की भूमि के ऊपर के साथ धागे की शुरूआत है, थोड़ी धीमी तो नग्न धागे होने के लिए जा रहा है।

आप यहाँ आस्थगित करें के बारे में अधिक पढ़ सकते हैं: http://eventmachine.rubyforge.org/EventMachine.html#M000486

जिसके अनुसार, पृष्ठ प्राप्त EventMachine का एक बड़ा प्रयोग है, लेकिन के रूप में अन्य पोस्टर कहा है, आप एक गैर अवरुद्ध आईओ लाइब्रेरी का उपयोग करें, और तब उपयोग करने की आवश्यकता next_tick या अपने कार्यों को शुरू करने के समान, बल्कि फिर डिफर करें, जो रिएक्टर लूप से आपके कार्य को तोड़ देता है।

+0

एफवाईआई लिंक टूटा हुआ है। –

24

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

जब आप EM.defer operation, callback चलाते हैं, तो ऑपरेशन रूबी-स्पॉन्डेड थ्रेड के अंदर चलाया जाता है, जो काम करता है, और फिर मुख्य लूप के अंदर कॉलबैक जारी किया जाता है। इसलिए, sleep 1operation में समानांतर में रन, लेकिन कॉलबैक क्रमानुसार चलाता है। यह रन टाइम में करीब 9-सेकंड अंतर बताता है।

यहां आपके द्वारा चलाए जा रहे कोड का सरलीकृत संस्करण है।

EM.run { 
    times = 0 

    work = proc { sleep 1 } 

    callback = proc { 
    sleep 1 
    EM.stop if (times += 1) >= 10 
    } 

    10.times { EM.defer work, callback } 
} 

इस बारे में 12 सेकंड, 1 समानांतर सोता है, धारावाहिक सोता के लिए 10 सेकंड के लिए दूसरा, और 1 भूमि के ऊपर के लिए पीछे नहीं है जो लेता है।

समानांतर में कॉलबैक कोड चलाने के लिए, यदि आप किसी प्रॉक्सी कॉलबैक तो जैसे EM.defer का उपयोग करता है का उपयोग करते हुए इसके लिए नए सूत्र अंडे देने के लिए है:

EM.run { 
    times = 0 

    work = proc { sleep 1 } 

    callback = proc { 
    sleep 1 
    EM.stop if (times += 1) >= 10 
    } 

    proxy_callback = proc { EM.defer callback } 

    10.times { EM.defer work, proxy_callback } 
} 

हालांकि, अगर आप इस में समस्याएं आती हैं हो सकता है यदि आपके कॉलबैक है फिर इवेंट लूप के भीतर कोड निष्पादित करना चाहिए, क्योंकि यह एक अलग, स्थगित थ्रेड के अंदर चलाया जाता है। यदि ऐसा होता है, तो समस्या कोड को प्रॉक्सी_callback proc के कॉलबैक में ले जाएं।

EM.run { 
    times = 0 

    work = proc { sleep 1 } 

    callback = proc { 
    sleep 1 
    EM.stop_event_loop if (times += 1) >= 5 
    } 

    proxy_callback = proc { EM.defer callback, proc { "do_eventmachine_stuff" } } 

    10.times { EM.defer work, proxy_callback } 
} 

इस संस्करण के बारे में 3 सेकंड है, जो समानांतर में ऑपरेशन के लिए सोने के 1 सेकंड, में भूमि के ऊपर के लिए समानांतर और 1 सेकंड कॉलबैक के लिए सोने के 1 सेकंड के लिए खातों में भाग गया।

+0

धन्यवाद बेन! मैंने आपका प्रॉक्सी उदाहरण थोड़ा और लिया है और एक अनब्लॉकिंग फ़ंक्शन बनाया है। आप यहां मेरा कार्यान्वयन देख सकते हैं: http://goo.gl/8kbc6y –

संबंधित मुद्दे