2013-05-14 18 views
17

मेरे रेल वेब ऐप में एपीआई और प्रोसेसिंग क्वेरी परिणाम को कॉल करने से दर्जनों तरीके हैं। इन विधियों निम्नलिखित संरचना है:रेल में समानांतर विधियों

def method_one 
    batch_query_API 
    process_data 
end 
.......... 
def method_nth 
    batch_query_API 
    process_data 
end 

def summary 
    method_one 
    ...... 
    method_nth 
    collect_results 
end 

कैसे मैं एक ही समय के बजाय रेल में अनुक्रमिक बिल्कुल क्वेरी तरीकों से चला सकते हैं (कई कार्यकर्ताओं ऊपर फायरिंग निश्चित रूप से, बिना)?

संपादित करें: सभी विधियों को एक एकल आवृत्ति चर से बुलाया जाता है। मुझे लगता है कि यह एक साथ नौकरियां जमा करने में साइडकीक या देरी के उपयोग को सीमित करता है।

+1

आप http://celluloid.io/ चाहते हैं, मुझे लगता है कि –

उत्तर

22

रूबी उत्कृष्ट promise मणि है। आपका उदाहरण इस तरह दिखेगा:

require 'future' 

def method_one 
... 
def method_nth 

def summary 
    result1 = future { method_one } 
    ...... 
    resultn = future { method_nth } 
    collect_results result1, ..., resultn 
end 

सरल, है ना? लेकिन चलिए अधिक जानकारी प्राप्त करते हैं।

result1 = future { method_one } 

इसका मतलब है, result1 पृष्ठभूमि में मूल्यांकन किया जा रहा है: यह एक भविष्य वस्तु है। आप इसे अन्य तरीकों से पास कर सकते हैं। लेकिन result1 के पास अभी तक कोई परिणाम नहीं है, यह अभी भी पृष्ठभूमि में प्रसंस्करण कर रहा है। एक थ्रेड के चारों ओर गुजरने के बारे में सोचो। लेकिन बड़ा अंतर यह है कि जिस क्षण आप को पढ़ते हैं, इसे पढ़ने के बजाए, यह उस बिंदु पर परिणाम के लिए ब्लॉक करता है और इंतजार करता है। तो उपरोक्त उदाहरण में, सभी result1 .. resultn चर पृष्ठभूमि में मूल्यांकन जारी रहेगा, लेकिन जब परिणाम एकत्र करने का समय आता है, और जब आप वास्तव में इन मानों को पढ़ने की कोशिश करते हैं, तो पठन उस बिंदु पर प्रश्नों को समाप्त करने की प्रतीक्षा करेंगे ।

promise मणि स्थापित करें और रूबी में नीचे कंसोल का प्रयास करें:

require 'future' 
x = future { sleep 20; puts 'x calculated'; 10 }; nil 
# adding a nil to the end so that x is not immediately tried to print in the console 
y = future { sleep 25; puts 'y calculated'; 20 }; nil 

# At this point, you'll still be using the console! 
# The sleeps are happening in the background 

# Now do: 
x + y 
# At this point, the program actually waits for the x & y future blocks to complete 

संपादित करें: result में टाइपो, result1 किया जाना चाहिए था, बदल echoputs

+0

एक सुरुचिपूर्ण समाधान! मैं फिर से 'वादा' मणि को देखने के लिए प्रेरित हूँ। – davogones

+0

@ आरडीएक्स: यह एक बहुत अच्छा समाधान प्रतीत होता है। क्या यह एक ऑब्जेक्ट के साथ काम करता है जो सभी विधियों को कॉल करता है? – AdamNYC

+1

@AdamNYC, हां, यह ऑब्जेक्ट स्तर की बजाय ब्लॉक/फ़ंक्शन स्तर पर काम करता है। इसका मतलब है कि आप कोड के किसी भी टुकड़े को समानांतर कर सकते हैं। (संपादित करें: आकस्मिक रूप से दबाए गए एंटर) – Subhas

0

आपको Sidekiq देखें।

RailsCasts साइडकीक के बारे में एपिसोड।

+0

मैं साइडकीक का उपयोग करता हूं, लेकिन इन सभी विधियों को एक आवृत्ति चर से कहा जाता है। क्या आप समझा सकते हैं कि आप साइडकीक के साथ ऐसा कैसे करेंगे? – AdamNYC

3

मान लें कि आपकी समस्या एक धीमी बाहरी एपीआई है, एक समाधान थ्रेड प्रोग्रामिंग या एसिंक्रोनस प्रोग्रामिंग का उपयोग हो सकता है। डिफ़ॉल्ट रूप से आईओ करते समय, आपका कोड अवरुद्ध हो जाएगा। इसका मूल रूप से अर्थ यह है कि यदि आपके पास कोई तरीका है जो कुछ JSON को पुनर्प्राप्त करने के लिए HTTP अनुरोध करता है तो आपकी विधि आपके ऑपरेटिंग सिस्टम को बताएगी कि आप सो रहे हैं और आप तब तक जागना नहीं चाहते हैं जब तक ऑपरेटिंग सिस्टम को प्रतिक्रिया न हो वह अनुरोध चूंकि इसमें कई सेकंड लग सकते हैं, इसलिए आपके आवेदन को केवल प्रतीक्षा करना होगा।

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

तो आपके मामले में सवाल यह है: क्या हमें वास्तव में एक और कॉल करने से पहले एक विधि का इंतजार करना होगा? यदि method_two का व्यवहार method_one के परिणाम पर निर्भर है, तो हां। लेकिन आपके मामले में, ऐसा लगता है कि वे सह-निर्भरता के बिना काम की व्यक्तिगत इकाइयां हैं। तो समवर्ती निष्पादन की संभावना है।

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

def main_method 
    Thread.new { method_one } 
    Thread.new { method_two } 
    Thread.new { method_three } 
end 

def method_one 
    # something_slow_that_does_an_http_request 
end 

def method_two 
    # something_slow_that_does_an_http_request 
end 

def method_three 
    # something_slow_that_does_an_http_request 
end 

कॉलिंग main_method तीनों विधियों क्या समानांतर प्रतीत होता है में निष्पादित करने के लिए कारण होगा। हकीकत में वे अभी भी अनुक्रमिक रूप से संसाधित किए जा रहे हैं, लेकिन method_one ब्लॉक पर सोने के बजाय, रूबी मुख्य थ्रेड पर वापस आ जाएगी और method_one थ्रेड पर वापस स्विच करेगा, जब ओएस इनपुट तैयार हो।

प्रत्येक विधि को मानने के लिए प्रतिक्रिया के लिए प्रतीक्षा को कम करने के लिए दो 2 एमएस लगते हैं, इसका मतलब है कि सभी तीन विधियां केवल 6 एमएस के बाद चल रही हैं - व्यावहारिक रूप से तत्काल।

यदि हम मानते हैं कि एक प्रतिक्रिया को पूरा करने के लिए 500 एमएस लगते हैं, तो इसका मतलब है कि आप अपना कुल निष्पादन समय 2 + 500 + 2 + 500 + 2 + 500 से 2 + 2 + 2 + 500 तक घटा सकते हैं - दूसरे में 1506 एमएस से शब्द केवल 506 एमएस तक।

ऐसा लगता है कि विधियां एक साथ चल रही हैं, लेकिन वास्तव में वे एक साथ सो रहे हैं।

आपके मामले में हालांकि आपको एक चुनौती है क्योंकि आपके पास एक ऑपरेशन है जो पिछले परिचालनों के सेट के पूरा होने पर निर्भर है। दूसरे शब्दों में, यदि आपके पास कार्य ए, बी, सी, डी, ई और एफ है, तो ए, बी, सी, डी और ई एक साथ प्रदर्शन किया जा सकता है, लेकिन एफ, ए, बी, सी, डी और ई तक निष्पादित नहीं किया जा सकता सब पूरा हो गए हैं।

इसे हल करने के कई तरीके हैं। आइए एक साधारण समाधान को देखें जो मुख्य धागे में एक नींद लूप बना रहा है जो समय-समय पर वापसी मूल्यों की एक सूची की जांच करता है ताकि यह सुनिश्चित किया जा सके कि कुछ शर्त पूरी हो गई है।

def task_1 
# Something slow 
return results 
end 

def task_2 
# Something slow 
return results 
end 

def task_3 
# Something slow 
return results 
end 

my_responses = {} 
Thread.new { my_responses[:result_1] = task_1 } 
Thread.new { my_responses[:result_2] = task_2 } 
Thread.new { my_responses[:result_3] = task_3 } 

while (my_responses.count < 3) # Prevents the main thread from continuing until the three spawned threads are done and have dumped their results in the hash. 
    sleep(0.1) # This will cause the main thread to sleep for 100 ms between each check. Without it, you will end up checking the response count thousands of times pr. second which is most likely unnecessary. 
end 

# Any code at this line will not execute until all three results are collected. 

ध्यान रखें कि बहुप्रचारित प्रोग्रामिंग कई कठिनाइयों के साथ एक मुश्किल विषय है। एमआरआई के साथ यह इतना बुरा नहीं है, क्योंकि एमआरआई खुशी से अवरुद्ध धागे के बीच स्विच करेगा, एमआरआई एक साथ दो धागे निष्पादित करने का समर्थन नहीं करता है और यह कुछ समेकन चिंताओं को हल करता है।

आप बहु प्रोग्रामिंग में प्राप्त करना चाहते हैं, मैं इस पुस्तक की सिफारिश: http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601

यह जावा के आसपास केंद्रित है, लेकिन नुकसान और बताया अवधारणाओं सार्वभौमिक हैं।

+0

क्या आप समझा सकते हैं कि मैं रेल ऐप में बहुप्रचारित प्रोग्रामिंग कैसे कार्यान्वित कर सकता हूं? क्या इससे कोई फर्क पड़ता है कि मेरे सभी तरीकों को किसी वस्तु से बुलाया जाना चाहिए? – AdamNYC

+0

नहीं, यह नहीं है। हालांकि, मल्टीथ्रेड प्रोग्रामिंग आपके प्रोग्राम प्रवाह को कैसे व्यवस्थित करने में एक मौलिक परिवर्तन का प्रतिनिधित्व करता है, इसलिए आपको अपनी समस्या के लिए बहुप्रचारित समाधान बनाने से पहले, इसे समझने में कुछ समय निवेश करना होगा। यह आपको एक शुरुआत देना चाहिए: http://www.tutorialspoint.com/ruby/ruby_multithreading.htm –

+1

शानदार प्रतिक्रिया! हालांकि, क्या आपका नमूना कोड हमेशा के लिए लटका नहीं होगा यदि धागे में से एक क्रैश हो और 'my_responses' में प्रवेश जोड़ने में विफल रहता है? आम तौर पर मैं धागे के माध्यम से पुन: प्रयास करता हूं और उन सभी में शामिल होता हूं। – davogones

4

लिए आप एक नया पर एक नज़र ले जा सकते हैं शहर में विकल्प: The futoroscope gem। जैसा कि आप blog post की घोषणा करके देख सकते हैं, यह एक ही समस्या को हल करने का प्रयास करता है, जो एक साथ एपीआई क्वेरी बना रहा है। ऐसा लगता है कि यह बहुत अच्छा समर्थन और अच्छा परीक्षण कवरेज है।

+0

धन्यवाद पाउलो। यह बहुत उपयोगी है। – AdamNYC

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