2015-09-18 17 views
10

मैंने एक प्रोग्राम लिखा है जो Parallel.ForEach का उपयोग कर सभी उपलब्ध कोर का उपयोग करता है। ForEach की सूची में ~ 1000 ऑब्जेक्ट्स हैं और प्रत्येक ऑब्जेक्ट के लिए गणना कुछ समय (~ 10 सेकंड) लेती है। इस परिदृश्य मैं सेटअप में इस तरह एक टाइमर:System.Timers.Timer बड़े पैमाने पर गलत

timer = new System.Timers.Timer(); 
timer.Elapsed += TimerHandler; 
timer.Interval = 15000; 
timer.Enabled = true; 

private void TimerHandler(object source, ElapsedEventArgs e) 
{ 
     Console.WriteLine(DateTime.Now + ": Timer fired"); 
} 

पल TimerHandler विधि पर यकीन है कि समस्या इस विधि के कारण नहीं है बनाने के लिए एक ठूंठ है।

मेरी उम्मीद थी कि TimerHandler विधि प्रत्येक ~ 15 सेकंड निष्पादित की जाएगी। हालांकि, इस विधि के लिए दो कॉल के बीच का समय भी 40 सेकंड तक पहुंचता है, इसलिए 25 सेकंड बहुत अधिक होते हैं। विधि के लिए new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount -1 } का उपयोग करके यह नहीं होता है और 15 सेकंड की अपेक्षित अंतराल देखी जाती है।

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

संपादित करें: जैसा कि युगल द्वारा इंगित किया गया है कि ThreadPool.SetMinThreads द्वारा पूल में निश्चित न्यूनतम धागे को समस्या हल हो गई है। मैंने Parallel.ForEach विधि के लिए new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount } (इसलिए -1 प्रारंभिक प्रश्न में) की कोशिश की और यह समस्या हल करती है। हालांकि, मेरे पास कोई अच्छी व्याख्या नहीं है कि इन संशोधनों ने समस्या का समाधान क्यों किया। हो सकता है कि इतने सारे थ्रेड बनाए गए कि टाइमर थ्रेड को "लंबे समय तक" खो दिया गया जब तक कि इसे फिर से निष्पादित नहीं किया गया।

+1

यदि आप समांतर लूप निष्पादित करने से पहले थ्रेड-पूल में धागे की संख्या को स्पष्ट रूप से सेट करते हैं, तो क्या यह अभी भी होता है? ('ThreadPool.SetMinThreads' का उपयोग करके) –

+0

क्या आप सभी प्रोसेसर का उपयोग करते समय प्रोसेसर उपयोग को घुमा रहे हैं? यदि हां, तो सभी घटनाएं संदेश पंप को कैसे संसाधित करती हैं, इस वजह से सभी घटनाएं धीमी प्रतिक्रिया देगी। – Jeremy

+1

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

उत्तर

1

Parallel कक्षा स्वयं प्रतिकृति कार्यों नामक एक आंतरिक टीपीएल सुविधा का उपयोग करती है। वे सभी उपलब्ध थ्रेड संसाधनों का उपभोग करने के लिए हैं। मुझे नहीं पता कि किस प्रकार की सीमाएं हैं लेकिन ऐसा लगता है कि यह सब उपभोग करने वाला है। मैंने कुछ दिनों पहले मूल रूप से एक ही सवाल का जवाब दिया है।

Parallel कक्षा किसी भी सीमा के बिना कार्यों की पागल मात्रा को बढ़ाने के लिए प्रवण है। असीमित धागे (2 प्रति सेकेंड) को शाब्दिक रूप से विकसित करने के लिए इसे उत्तेजित करना आसान है। मैं मैन्युअल रूप से निर्दिष्ट अधिकतम-डीओपी के बिना Parallel वर्ग अनुपयोगी मानता हूं। यह एक समय बम है जो लोड में यादृच्छिक रूप से उत्पादन में विस्फोट करता है।

Parallel एएसपी.NET परिदृश्यों में विशेष रूप से जहरीला है जहां कई अनुरोध एक थ्रेड-पूल साझा करते हैं।

अद्यतन: मैं मुख्य बिंदु बनाना भूल गया। टाइमर टिक थ्रेड पूल में कतारबद्ध हैं। यदि पूल संतृप्त है तो वे लाइन में आते हैं और बाद में निष्पादित होते हैं। (यही कारण है कि टाइमर टिक एक साथ हो सकती है या टाइमर बंद होने के बाद।) यह बताता है कि आप क्या देख रहे हैं। पूल ओवरलोडिंग को ठीक करने का तरीका है।

इस विशेष परिदृश्य के लिए सबसे अच्छा तय एक निश्चित कार्य शेड्यूलर होगा जिसमें निश्चित मात्रा में धागे होंगे। Parallel उस कार्य शेड्यूलर का उपयोग करने के लिए किया जा सकता है। समानांतर एक्सटेंशन एक्स्ट्रा में ऐसा शेड्यूलर होता है। वैश्विक स्तर पर साझा थ्रेड पूल से उस काम को प्राप्त करें। आम तौर पर, मैं PLINQ को पुन: संकुचित करता हूं लेकिन वह शेड्यूलर नहीं ले पाता है। एक अर्थ में समानांतर और PLINQ दोनों अनिवार्य रूप से अपंग एपीआई हैं।

ThreadPool.SetMinThreads का उपयोग न करें। वैश्विक प्रक्रिया व्यापक सेटिंग्स के साथ गड़बड़ मत करो। बस गरीब धागा पूल अकेले छोड़ दें।

इसके अलावा, Environment.ProcessorCount -1 का उपयोग न करें क्योंकि यह एक कोर को बर्बाद करता है।

टाइमर लिए पहले से कोई धागा

टाइमर ओएस कर्नेल में एक डेटा संरचना है में मार डाला गया है। जब तक एक टिक कतारबद्ध नहीं हो जाती तब तक कोई धागा नहीं होता है। निश्चित नहीं है कि यह वास्तव में कैसे काम करता है लेकिन टिक अंततः .NET में थ्रेड पूल में कतारबद्ध है। समस्या तब शुरू होने पर है।

एक समाधान के रूप में आप एक थ्रेड अनुकरण करने के लिए एक लूप में सोते धागे को शुरू कर सकते हैं। यह एक हैक है, हालांकि, क्योंकि यह मूल कारण को ठीक नहीं करता है: ओवरलोडेड थ्रेड पूल।

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