2012-02-21 19 views
16

एक पैटर्न के बेवकूफ रूबी एनालॉग क्या है जो संभावित रूप से स्थगित असीमित गणना का प्रतिनिधित्व करता है जिसके पूरा होने की सदस्यता लेने की संभावना है? यानी .NET System.Threading.Task, या पायथन 3.x concurrent.futures.future की लाइनों के साथ कुछ।रुबी में कार्य/भविष्य

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

+0

कुछ backgroundrb के साथ मदद कर सकता है, बाहर की जाँच की तरह लगता है: http://backgroundrb.rubyforge.org/workers/ यह एक वेब स्टैक (वेब ​​सर्वर डाटाबेस कैश??) शामिल है # hopingfor + 100rep – edwardsharp

+0

@edwardsharp नहीं , इसमें एक वेब स्टैक शामिल नहीं है। खैर, यह वास्तव में, लेकिन यह उससे अधिक सामान्य हो सकता है - यह एसिंक्रोनस ऑपरेशंस डब्ल्यू/कॉलबैक विशेष रूप से एपीआई के बारे में है, इस पर ध्यान दिए बिना कि वास्तव में एसिंक्रोनि वास्तव में कैसे लागू किया जाता है। –

+0

ग्रेट पढ़ा, एक बेवकूफ भविष्य एपीआई लागू करता है, मदद कर सकता है। http://tx.pignata.com/2012/11/concurrency-patterns-in-ruby-futures.html – mwoods79

उत्तर

1

फाइबर?

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

+0

यह एसिंक्रोनि के बारे में अधिक से अधिक समवर्तीता के बारे में नहीं है। मान लीजिए कि मेरे पास पहले से ही एक लाइब्रेरी है जो रूबी में _not_ लिखा गया है, लेकिन जो वायदा देता है (उदा। यह एक .NET लाइब्रेरी है और यह सिस्टम देता है। थ्रेडिंग टास्क)। मुझे यह जानने की ज़रूरत है कि रुबी में इस तरह से सबसे अच्छा प्रदर्शन कैसे किया जाए जो रूबी डेवलपर्स के लिए सबसे अधिक प्राकृतिक लगेगा। –

+0

फाइबर वास्तव में समवर्तीता के बारे में नहीं है, यह गैर-अवरुद्ध मॉडल है, यानी एसिंक्रोनि, जैसे node.js. आप रूबी फ्रेमवर्क में इस तकनीक के उपयोग की जांच कर सकते हैं http://postrank-labs.github.com/goliath/ – megas

+0

मैं इसे समझता हूं। फिर भी, जहां तक ​​मैं देख सकता हूं, फाइबर सभी या कुछ भी नहीं हैं - यानी यदि आप शामिल कुछ एपीआई के कार्यान्वयन को नियंत्रित नहीं करते हैं, और वे fiber का उपयोग नहीं करते हैं, तो आप वास्तव में स्वयं का उपयोग नहीं कर सकते हैं क्योंकि आप को उपज करने के लिए एक फाइबर नहीं होगा। मुझे किसी उच्चतम स्तर की आवश्यकता है जो कि किसी दिए गए मामले में एसिंक्रोनि के कार्यान्वयन विनिर्देशों पर आधारित है, और किसी भी प्रकार के एसिंक ऑपरेशन के लिए सार्वभौमिक सामान्य इंटरफ़ेस प्रस्तुत करता है। –

9

मुझे वेनिला रूबी के बारे में निश्चित नहीं है, लेकिन EventMachine deferrables है।

इसके अलावा, this article देखें।

EM.run { 
    detector = LanguageDetector.new("Sgwn i os yw google yn deall Cymraeg?") 
    detector.callback { |lang| puts "The language was #{lang}" } 
    detector.errback { |error| puts "Error: #{error}" } 
} 
+0

यदि कोर रूबी में मानक पैटर्न की कमी है, तो मुझे वास्तव में यह देखना होगा कि विभिन्न ढांचे को देखने के लिए क्या पेशकश की जाती है कि क्या एक सामान्य पैटर्न प्राप्त किया जा सकता है। यह एक अच्छा सूचक है - क्या आप किसी अन्य ढांचे के बारे में जानते हैं जिनके पास कुछ समान है? –

+0

@PavelMinaev: मेरे सिर के शीर्ष से - नहीं। लेकिन मैं इसके बारे में सोचूंगा :) –

1

आप पर एक कॉलबैक होने से resque
की तरह एक नौकरी कतार उपयोग कर सकते हैं एक बच्चे की प्रक्रिया

rd, wr = IO.pipe 

p1 = fork do 
    rd.close 
    # sleep is for demonstration purpose only 
    sleep 10 
    # the forked child process also has a copy of the open file 
    # handles, so we close the handles in both the parent and child 
    # process 
    wr.write "1" 
    wr.close 
end 

wr.close 

puts "Process detaching | #{Time.now}" 
Process.detach(p1) 
puts "Woot! did not block | #{Time.now}" 

1.upto(10) do 
    begin 
    result = rd.read_nonblock(1) 
    rescue EOFError 
    break 
    rescue Exception 
    # noop 
    end 

    puts "result: #{result.inspect}" 
    system("ps -ho pid,state -p #{p1}") 
    sleep 2 
end 

rd.close 

__END__ 

ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0] 
Process detaching | 2012-02-28 17:05:49 +0530 
Woot! did not block | 2012-02-28 17:05:49 +0530 
result: nil 
    PID STAT 
5231 S+ 
result: nil 
    PID STAT 
5231 S+ 
result: nil 
    PID STAT 
5231 S+ 
result: nil 
    PID STAT 
5231 S+ 
result: nil 
    PID STAT 
5231 S+ 
result: "1" 
    PID STAT 
  • forking द्वारा शुद्ध माणिक

    1. के कुछ त्वरित उदाहरण कोडित है एक धागा

      require 'thread' 
      
      Thread.abort_on_exception = true 
      
      module Deferrable 
          def defer(&block) 
          # returns a thread 
          Thread.new do 
           # sleep is for demonstration purpose only 
           sleep 10 
      
           val = block.call 
           # this is one way to do it. but it pollutes the thread local hash 
           # and you will have to poll the thread local value 
           # can get this value by asking the thread instance 
           Thread.current[:human_year] = val 
           # notice that the block itself updates its state after completion 
          end 
          end 
      end 
      
      class Dog 
          include Deferrable 
          attr_accessor :age, :human_age 
          attr_accessor :runner 
      
          def initialize(age=nil) 
          @age = age 
          end 
      
          def calculate_human_age_as_deferred! 
          self.runner = defer do 
           # can do stuff with the values here 
           human_age = dog_age_to_human_age 
           # and finally publish the final value 
           after_defer { self.human_age = human_age } 
           # return value of the block. used in setting the thread local 
           human_age 
          end 
          end 
      
          protected 
          def dog_age_to_human_age 
          (self.age/7.0).round(2) 
          end 
      
          def after_defer(&block) 
          block.call 
          end 
      end 
      
      dog = Dog.new(8) 
      dog.calculate_human_age_as_deferred! 
      
      1.upto(10) do 
          sleep 2 
          puts "status: #{dog.runner.status} | human_age: #{dog.human_age.inspect}" 
          break unless dog.runner.status 
      end 
      
      puts "== using thread local" 
      
      dog = Dog.new(8) 
      dog.calculate_human_age_as_deferred! 
      
      1.upto(10) do 
          sleep 2 
          puts "status: #{dog.runner.status} | human_age: #{dog.runner[:human_year].inspect}" 
          break unless dog.runner.status 
      end 
      
      __END__ 
      
      ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0] 
      status: sleep | human_age: nil 
      status: sleep | human_age: nil 
      status: sleep | human_age: nil 
      status: sleep | human_age: nil 
      status: false | human_age: 1.14 
      == using thread local 
      status: sleep | human_age: nil 
      status: sleep | human_age: nil 
      status: sleep | human_age: nil 
      status: sleep | human_age: nil 
      status: false | human_age: 1.14 
      

    धागे एक बच्चे प्रक्रिया forking लेकिन forking मजबूत है की तुलना में कम स्मृति खपत करते हैं। धागे में एक अनचाहे त्रुटि पूरे सिस्टम को नीचे ला सकती है। जबकि एक बच्चे की प्रक्रिया में एक बिना क्रिया त्रुटि, इकलौती संतान प्रक्रिया

    अन्य लोगों को फाइबर और eventmachine ने बताया है नीचे लाना होगा (ईएम का उपयोग कर :: Deferrable और EM.defer) एक और विकल्प

    रेशे और धागे की जरूरत है सावधानीपूर्वक कोडिंग। कोड सूक्ष्म तरीकों से गलत हो सकता है। इसलिए codebase अच्छी तरह व्यवहार किया जाना

    Eventmachine तेज है
    इसके अलावा फाइबर रिक्तिपूर्व बहुकार्यन का उपयोग, लेकिन यह एक विशेष दुनिया (जैसे अजगर में मुड़) है। इसका अपना अलग आईओ स्टैक है, इसलिए सभी पुस्तकालयों को इवेंटमाचिन का समर्थन करने के लिए लिखा जाना चाहिए। ऐसा कहने के बाद, मुझे नहीं लगता कि लाइब्रेरी समर्थन इवेंटमाचिन

  • +0

    मैं एसिंक्रोनि को लागू नहीं कर रहा हूं, मैं कुछ ऐसा उजागर कर रहा हूं जो रूबी को पहले से लागू किया गया है। "सवाल ऑब्जेक्ट के उपयोगकर्ता को प्रस्तुत एपीआई के साथ कड़ाई से चिंतित है।" –

    +0

    @PavelMinaev अगर मुझे सही टिप्पणी मिलती है। आप एक गैर-आक्रामक समाधान चाहते हैं? दोनों समाधान थोड़ा आक्रामक हैं। उदाहरण के लिए मैंने कोड के चारों ओर एक रैपर का उपयोग करना होगा। हमेशा – deepak

    +0

    से एक मणि बना सकते हैं कल्पना कीजिए कि मेरे पास एक डीएलएल है, जो सी में लिखा गया है, जो एक एसिंक्रोनस फ़ंक्शन का खुलासा करता है। एसिंक्रोनि कॉलबैक के रूप में है - यानी आप इसे कॉल करते हैं, और अपना कॉलबैक प्रदान करते हैं जिसे ऑपरेशन करने के बाद बुलाया जाता है। यह वास्तव में कार्यान्वित किया गया है एक कार्यान्वयन विस्तार - डीएलएल धागे या फाइबर या कुछ और उपयोग कर सकते हैं। रूबी कोड के लिए मूर्खतापूर्ण तरीके से रूबी कोड को उस फ़ंक्शन को लपेटने और उजागर करने की आवश्यकता है, लेकिन मैं इसके कार्यान्वयन को स्पर्श नहीं कर सकता। –

    1

    शायद मुझे कुछ याद आ रही है, लेकिन अगर स्थिति गहराई से आपकी प्रतिक्रिया में वर्णित है, तो क्यों सी एपीआई को रूबी के रूप में लपेटें विस्तार और एक रूबी विधि प्रदान करें जो आपके आवश्यक कॉलबैक से संबंधित ब्लॉक स्वीकार करता है? यह भी बहुत मूर्खतापूर्ण रूबी होगा।

    रूबी 1.9: http://media.pragprog.com/titles/ruby3/ext_ruby.pdf के लिए अपडेट की गई "पिकैक्स" पुस्तक से रू के साथ रूबी को विस्तारित करने के साथ एक नमूना अध्याय है।

    अद्यतन: यहाँ कुछ रूबी में रूबी अपवादों के साथ और यह सी इंटरफ़ेस है में काम कर लिंक्स हैं।

    +0

    यह एक संभावना है, अगर यह चीजों को करने का मानक तरीका है। यह अभी भी कुछ और प्रश्न आमंत्रित करता है, उदा। यदि परिणाम कॉलबैक को इसके तर्क के रूप में प्रचारित किया जाता है, तो त्रुटियों (अपवाद) को प्रचारित कैसे किया जाना चाहिए? –

    +0

    आप ऐसा ही कर सकते हैं जैसा कि आप किसी भी रूबी लाइब्रेरी के लिए अपवाद फेंक कर ऐसा करेंगे। यह सी में किया जा सकता है क्योंकि रुबी सी इंटरफ़ेस आपको मूल रूप से कुछ भी करने की अनुमति देता है जो आप रूबी इन सी में कर सकते हैं (अधिक verbosely पढ़ें), या यह रूबी रैपर में किया जा सकता है। मैं सी इंटरफ़ेस के अंदर और बाहर रूबी अपवादों पर कुछ लिंक के साथ अपना उत्तर अपडेट करूंगा। – drnewman

    +0

    चूंकि फ़ंक्शन असीमित रूप से निष्पादित करता है, इसलिए जो भी त्रुटि/अपवाद फेंक देगा, उसे भी असीमित रूप से रिपोर्ट किया जाएगा। अर्थात। जब आप इसे 'foo ({| result | ...}) कहते हैं, तो यह कॉल के बिंदु पर अपवाद नहीं फेंक सकता है, क्योंकि उसने अभी तक निष्पादन शुरू नहीं किया है। इसके बजाय, इसे कॉलबैक के अपवाद को प्रसारित करने की आवश्यकता है। इसे एक अतिरिक्त पैरामीटर के रूप में पास करना, यानी 'foo ({| परिणाम, err | ...})' एक विकल्प है। दूसरा कच्चे नतीजे के बजाए एक वादा पास कर रहा है, यानी 'foo ({| वादा | परिणाम = वचन.result ...})', और फिर 'वादा .result' अगर कोई त्रुटि हुई तो फेंक देगा। –

    1

    lazy.rb "वायदा" प्रदान करता है, लेकिन वे बिल्कुल वैसा ही आप का वर्णन के रूप में होने के लिए नहीं है (या मैं उम्मीद होती है):

    इसके अतिरिक्त, लाइब्रेरी वायदा प्रदान करती है, जहां एक गणना तुरंत चलती है एक पृष्ठभूमि धागे में।

    तो, आप बाद में उनकी गणना नहीं कर सकते हैं, या अन्य तरीकों से उनमें से मूल्य (नेटवर्क से शायद) सम्मिलित नहीं कर सकते हैं।

    +0

    यह अभी भी एक अच्छा सूचक है - भले ही उन चीजों को कार्यान्वित किया गया हो, उनकी एपीआई सतह को देखकर उपयोगी हो। दुर्भाग्यवश, वे वास्तव में सरल दिखते हैं; विशेष रूप से, भविष्य के पूरा होने के लिए सब्सक्राइब करने का कोई तरीका नहीं है, आप केवल तब तक ब्लॉक कर सकते हैं जब तक यह आपको नतीजा न दे। –

    +0

    मुझे यकीन नहीं है कि सब्सक्राइब करके आपका क्या मतलब है; क्या तुम्हारा यह मतलब था? http://msdn.microsoft.com/en-us/library/dd270696.aspx –

    +0

    हां, बहुत कुछ। जरूरी नहीं कि इस तरह चेनने योग्य, यद्यपि - उदा। पाइथन 3.x में मानक मॉड्यूल 'concurrent.futures' में' Future.add_done_callback' देखें। –

    1

    मैंने पाया यह अत्यंत उपयोगी होने के लिए:

    https://github.com/wireframe/backgrounded

    यह एक मणि कि बस एक पृष्ठभूमि कार्य पर तरीकों को आगे बढ़ाने के लिए अनुमति देता है।

    0

    thread मणि ब्याज का हो सकता है। आप एक थ्रेड-पूल बना सकते हैं जो पृष्ठभूमि में सामान को संसाधित करता है। मणि भविष्य, देरी इत्यादि जैसी कई अन्य सुविधाओं का भी समर्थन करता है। the github repo पर एक नज़र डालें।

    यह रूबी संस्करणों की विस्तृत श्रृंखला के साथ काम करता है, न केवल 1.9+, इसलिए मैं इसका उपयोग करता हूं।