2011-04-16 24 views
25

मेरे पास एक लूप है जहां पुनरावृत्ति पर गणना i पिछले पुनरावृत्तियों में किए गए गणनाओं पर निर्भर नहीं है।लूप के लिए समानांतर

मैं for लूप (मेरा कोड जावा में है) को समानांतर करना चाहता हूं ताकि एकाधिक पुनरावृत्तियों की गणना कई प्रोसेसर पर एक साथ चल सकें। क्या मुझे प्रत्येक पुनरावृत्ति की गणना के लिए धागा बनाना चाहिए, यानी बनाए जाने वाले धागे की संख्या पुनरावृत्तियों की संख्या के बराबर है (लूप के लिए पुनरावृत्तियों की संख्या बड़ी है)? यह कैसे करना है?

उत्तर

10

आपको मैन्युअल रूप से थ्रेड हैंडलिंग नहीं करना चाहिए। इसके बजाए:

  • reasonably-sized thread pool executor service बनाएं (यदि आपकी गणना कोई आईओ नहीं है, तो आपके पास कोर के रूप में कई धागे का उपयोग करें)।
  • एक लूप चलाएं जो निष्पादक सेवा में प्रत्येक व्यक्तिगत गणना सबमिट करता है और परिणामी Future ऑब्जेक्ट्स रखता है। ध्यान दें कि यदि प्रत्येक गणना में केवल थोड़ी सी मात्रा होती है, तो इससे बहुत अधिक ओवरहेड बन जाएगा और संभवत: एकल-थ्रेडेड प्रोग्राम से धीमे हो सकते हैं। उस स्थिति में, एमडीएमए के रूप में गणना के पैकेट्स करने वाली नौकरियां सबमिट करें।
  • भागो एक दूसरे पाश है कि सभी Future रों से परिणाम एकत्र करता है (यह परोक्ष जब तक सभी संगणना समाप्त कर दिया है इंतजार करेंगे)
  • निष्पादक सेवा
+0

पहले पाश भी 'invokeAll के लिए एक एकल कॉल()' द्वारा बदला जा सकता है चाहेंगे। –

+0

@ पीटर: ज्यादातर मामलों में, आपको सभी कॉलबल के निर्माण के लिए एक लूप चलाने की ज़रूरत होगी, वैसे भी उन्हें उस समय सबमिट कर सकते हैं। –

+0

सत्य, जब तक कि कोई व्यक्ति अपनी प्रसंस्करण से कार्यों की तैयारी को अलग नहीं करना चाहता। –

2

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

यदि आप जावा से पूरी तरह से जुड़े नहीं हैं, तो आप OpenMPI जैसे समानांतर उच्च-प्रदर्शन सी सिस्टम को आजमा सकते हैं। ओपनएमपीआई इस तरह की समस्या के लिए उपयुक्त है।

+0

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

0

धागे स्वयं को न बनाएं। मैं आपको फोर्क/जॉइन फ्रेमवर्क (jsr166y) का उपयोग करने की सलाह देता हूं और आइटमों की एक निर्दिष्ट श्रृंखला पर फिर से काम करता हूं। हार्डवेयर समर्थन के रूप में कई धागे का उपयोग करके, यह आपके लिए थ्रेड प्रबंधन का ख्याल रखेगा।

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

jsr166z में एक समांतर आरे वर्ग भी है, जो एक सरणी पर बार-बार गणना की अनुमति देता है। यह आपके लिए काम कर सकता है, यदि आपके द्वारा गणना की जाने वाली मान आदिम प्रकार हैं।

45

यहां एक छोटा सा उदाहरण है कि आप समांतरता के साथ शुरुआत करने में सहायक हो सकते हैं। यह मानता है कि:

  1. आप Input ऑब्जेक्ट बनाते हैं जिसमें आपके गणना के प्रत्येक पुनरावृत्ति के लिए इनपुट होता है।
  2. आप Output ऑब्जेक्ट बनाते हैं जिसमें प्रत्येक पुनरावृत्ति के इनपुट की गणना करने से आउटपुट होता है।
  3. आप इनपुट की एक सूची में उत्तीर्ण होना चाहते हैं और एक ही बार में आउटपुट की एक सूची वापस प्राप्त करना चाहते हैं।
  4. आपका इनपुट काम करने का एक उचित हिस्सा है, इसलिए ओवरहेड बहुत अधिक नहीं है।

यदि आपकी गणना वास्तव में सरल है तो आप शायद उन्हें बैचों में प्रसंस्करण पर विचार करना चाहेंगे। आप प्रत्येक इनपुट में 100 कहकर ऐसा कर सकते हैं। यह आपके सिस्टम में प्रोसेसर के रूप में कई धागे का उपयोग करता है। यदि आप पूरी तरह से सीपीयू गहन कार्यों से निपट रहे हैं तो शायद वह संख्या जो आप चाहते हैं। आप अगर वे कुछ और (डिस्क, नेटवर्क, डेटाबेस, आदि) के लिए इंतज़ार कर अवरुद्ध कर देते हैं उच्च जाने के लिए

public List<Output> processInputs(List<Input> inputs) 
     throws InterruptedException, ExecutionException { 

    int threads = Runtime.getRuntime().availableProcessors(); 
    ExecutorService service = Executors.newFixedThreadPool(threads); 

    List<Future<Output>> futures = new ArrayList<Future<Output>>(); 
    for (final Input input : inputs) { 
     Callable<Output> callable = new Callable<Output>() { 
      public Output call() throws Exception { 
       Output output = new Output(); 
       // process your input here and compute the output 
       return output; 
      } 
     }; 
     futures.add(service.submit(callable)); 
    } 

    service.shutdown(); 

    List<Output> outputs = new ArrayList<Output>(); 
    for (Future<Output> future : futures) { 
     outputs.add(future.get()); 
    } 
    return outputs; 
} 
+0

यह बहुत अच्छा काम करता है .. यह कांटा से अलग कैसे है और शामिल हो। अगर मैं गलत हूं तो कृपया ध्यान न दें कि मैं सिर्फ नौसिखिया उपयोगकर्ता हूं – CTsiddharth

+0

+1 अच्छा टुकड़ा, thx – Jakob

+0

अच्छा जवाब @ व्हाइटफैंग 34 –

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