2012-04-13 17 views
5

मेरे पास मेरे एल्गोरिदम में एक विधि है जो डेटा के बहुत बड़े सेट पर बहुत तंग पाश चलाती है। मैंने मूल रूप से इसे सिंगल-थ्रेडेड लिखा था जो ठीक था, लेकिन इसमें काफी समय लगा। मैं अब इसे गति देने के लिए बिंदु पर हूं, इसलिए अब मैं काम को समानांतर करने के लिए थ्रेडपूल का उपयोग कर रहा हूं। समस्या यह है कि इससे मेरा सीपीयू उपयोग 95-100% तक पहुंच जाता है, जिसे मैं उम्मीद करता हूं। हालांकि, मेरा प्रदर्शन नाटकीय रूप से बढ़ गया है, लेकिन मुझे लगता है कि अगर मैं सभी संदर्भ स्विचिंग पर कटौती कर सकता हूं तो मैं इसे बेहतर बना सकता हूं। यह मेरे अन्य कार्यक्रमों को थोड़ी देर तक ले जाने का कारण बनता है क्योंकि उन्हें सीपीयू संसाधनों के लिए धागे से लड़ना पड़ता है।तंग लूप में थ्रेडपूल कॉलबैक - 100% सीपीयू

मेरा सवाल यह है कि मैं इसे करने के बारे में कैसे जाना चाहिए? एकमात्र चीज जिसे मैं सोचने में सक्षम हूं, एक समय में चल रहे धागे की संख्या को सीमित करना है, लेकिन यह मेरे एल्गोरिदम धीमा कर सकता है क्योंकि केवल कुछ धागे एक ही समय में चलने में सक्षम होंगे। मैं अपने धागे में नींद नहीं जोड़ना चाहता हूं क्योंकि मुझे जितनी जल्दी हो सके पूरा होने के लिए एल्गोरिदम की आवश्यकता है।

संपादित करें: कई लोगों ने टीपीएल का उपयोग करने का उल्लेख किया है। मुझे लगता है कि यह एक अच्छा विचार है, लेकिन दुर्भाग्य से मैं यह उल्लेख करना भूल गया कि मैं .NET 3.5 का उपयोग कर फंस गया हूं क्योंकि मूल एप्लिकेशन ने अभी तक .NET 4 का उपयोग करके एक संस्करण जारी नहीं किया है।

+1

यदि आप गति चाहते हैं, तो आप सभी तेज चीजें क्यों निकाल लेंगे? संदर्भ स्विच ओएस द्वारा किया जाता है, आप इसके साथ गड़बड़ नहीं करते हैं ... – gbianchi

+1

समाधान पूल में धागे की प्राथमिकता को कम करना है। यह कोई जवाब नहीं है क्योंकि मुझे नहीं पता कि इसे कुशलता से कैसे किया जाए :( –

+0

लगता है जैसे आपको व्यक्तिगत कार्यों को बड़ा बनाना चाहिए। ओटीओएच, थ्रेडपूल आपके द्वारा सुझाए गए अधिकांश कार्यों को पहले से ही करने के लिए पर्याप्त स्मार्ट है। यदि आपके पास और कार्य हैं सीपीयू की तुलना में, यह अधिक धागे शुरू करने के बजाय उन्हें कतारबद्ध करेगा। –

उत्तर

6

यह सब संसाधन प्रबंधन के बारे में है। आपका कार्यक्रम वर्तमान में सभी संसाधनों को हॉगिंग कर रहा है, और इसलिए अन्य कार्यक्रमों तक पहुंच कम हो जाती है। आपको "जितना जल्दी हो सके पूरा करने के लिए चलाने के लिए एल्गोरिदम की आवश्यकता है" भाग को संतुलित करने की आवश्यकता है, "यह मेरे अन्य कार्यक्रमों को थोड़ा सा कठोर होने का कारण बनता है क्योंकि उन्हें CPU संसाधनों के लिए धागे से लड़ना है"। वे पारस्परिक रूप से अनन्य हैं; आप अपने ऐप को जितनी जल्दी हो सके उतनी तेजी से नहीं चला सकते जितना संभवतः किसी विशेष मशीन पर कर सकते हैं और अन्य ऐप्स को पूरी तरह उत्तरदायी भी रख सकते हैं। सीपीयू किसी भी समय में कितना कर सकता है इसकी सीमा है।

जहाँ तक दक्षता लाभ के रूप में, वहाँ कुछ चीजें आप कर सकते हैं:

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

  • हां, आप धागे की संख्या को "थ्रॉटल" करने में सक्षम होना चाहेंगे। यह दोनों प्रोग्रामों को आपके प्रोग्राम की आवश्यकता को कम करके कुछ CPU समयों को अनुमति देने के लिए है, लेकिन जैसा कि मैंने कहा, मल्टीथ्रेडिंग में भी ओवरहेड निहित है। अंगूठे का नियम यह है कि यदि एक सीपीयू को सक्रिय रूप से चलने वाले धागे की गिनती से अधिक दिया जाता है क्योंकि इसमें "निष्पादन इकाइयां" होती हैं (ये एक सीपीयू चिप पर भौतिक कोर होते हैं, और "तार्किक प्रोसेसर" जैसे हाइपर थ्रेडिंग तकनीक जो एक कोर को विभाजित करती है दो में), तो ओएस वास्तव में धागे को चलाने में खर्च करने के बजाय थ्रेड शेड्यूलिंग और उनके बीच स्विचिंग ("कैश-थ्रैशिंग") में अधिक समय बिताएगा। अधिक सामान्य शब्दों में, रिटर्न कम करने का एक कानून है, जो "पैमाने की बीमारियों" में प्रगति करेगा; आखिरकार, एक और धागा जोड़ना आपके प्रोग्राम को धीरे-धीरे चलाने के लिए प्रेरित करेगा यदि आपने उस धागे का उपयोग नहीं किया था। हां, थ्रेडपूल आपके लिए अधिकतम धागे को संभालता है, लेकिन यह शायद अपने स्वयं के एल्गोरिदम में लागू करने के लिए अपनी विभिन्न सुविधाओं का सबसे सरल है।

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

+0

सिर्फ ओ (मेरे भगवान) के लिए +1 - महान उत्तर ;-) – BrokenGlass

+1

'अंगूठे का नियम यह है कि यदि एक सीपीयू को सक्रिय रूप से चलने वाले धागे की गिनती से दोगुना से अधिक दिया जाता है "निष्पादन इकाइयां" (ये एक सीपीयू चिप पर भौतिक कोर हैं, और "लॉजिकल प्रोसेसर" जैसे हाइपर थ्रेडिंग तकनीक जो एक कोर को दो में विभाजित करती है), फिर ओएस थ्रेड को शेड्यूल करने और उनके बीच स्विच करने में अधिक समय व्यतीत करेगा ("कैश-थ्रैशिंग") इससे वास्तव में धागे को चलाने में खर्च किया जाएगा - क्या आपने वास्तव में यह कोशिश की है? अप्रबंधित कोड पर, इससे कोई फर्क नहीं पड़ता कि आपके पास 8 सीपीयू-बाध्य धागे या 800 हैं - लगभग उसी काम की मात्रा पूरी हो जाती है। –

+0

तो यदि मेरे पास कोर i7 CPU (4 भौतिक कोर + 4 आभासी कोर) हैं, तो 16 धागे उस नियम के अनुसार सीमा है? –

2

आप एक IEnumerable पर एक foreach लूप में अपने मुख्य आवेदन पुनर्लेखन कर सकते हैं आप PLINQ का उपयोग अपने पाश parallelize कर सकते हैं। आप WithDegreeOfParallelism का उपयोग यह नियंत्रित करने के लिए कर सकते हैं कि आपका एप्लिकेशन कितने कोर का उपयोग करेगा। आप अपने कंप्यूटर पर सभी कोरों का उपयोग न करके अनुभव किए गए कुछ "अंतराल" को रोक सकते हैं। साथ ही, आपको अनावश्यक संसाधन विवाद से बचने के लिए धागे में अपने लूप को विभाजित करने के तरीके से निपटने की ज़रूरत नहीं है। PLINQ आपके लिए यह सब करता है।

मान लिया जाये कि आप इस बहुत ही सरल एकल पिरोया पाश है:

var arrayOfStuff = new[] { ... }; 
for (var i = 0; i < arrayOfStuff.Length; ++i) 
    DoSomething(arrayOfStuff[i]); 

आदेश कोई फर्क नहीं पड़ता अगर आप एक कोर की तुलना में कम का उपयोग कर PLINQ का उपयोग कर इसे parallelize कर सकते हैं उपलब्ध है:

var cores = Math.Max(1, Environment.ProcessorCount - 1); 
arrayOfStuff.AsParallel().WithDegreeOfParallelism(cores).ForAll(DoSomething); 

भी यदि आपका मुख्य पाश अधिक जटिल है तो आप इसे एक पुनरावर्तक ब्लॉक में फिर से लिख सकते हैं जिसे आप समांतर बना सकते हैं:

IEnumerable<Stuff> GetStuff() { 
    for (... very complex looping ...) { 
    ... 
    yield return stuff; 
    } 
}