2012-06-01 16 views
5

शायद मैं यह सही समझ में नहीं आया ... सभी समानांतर वर्ग मुद्दा :(सिस्टम का उपयोग करना। थ्रेडिंग। टास्क। समानांतर थ्रेड पूल में नया धागा बनाएं?

लेकिन अब मैं क्या पढ़ रहा हूँ से, मैं समझता हूँ कि जब मैं समानांतर का उपयोग मैं वास्तव में लामबंद सभी धागे कि ThreadPool में मौजूद है कुछ कार्य/मिशन के लिए

उदाहरण के लिए:।।

var arrayStrings = new string[1000]; 
    Parallel.ForEach<string>(arrayStrings, someString => 
    { 
     DoSomething(someString); 
    }); 

तो इस मामले में Parallel.ForEach जुटाने है सभी धागे कि 'DoSomething' कार्य/मिशन के लिए ThreadPool में मौजूद है

लेकिन कॉल समानांतर है। फोरेक कोई भी नया धागा तैयार करेगा?

यह स्पष्ट है कि कोई 1000 नए धागे नहीं होंगे। लेकिन मान लें कि 1000 नए धागे हैं, कुछ मामला है कि थ्रेडपूल उस थ्रेड को जारी करता है जो इस तरह से होता है, इस मामले में ... समानांतर। किसी भी नए धागे को बनाएगा?

+0

['समानांतर। फोरेच '] (http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx) -" एक foreach निष्पादित करता है (प्रत्येक के लिए Visual Basic में) ऑपरेशन जिसमें पुनरावृत्तियों ** ** समानांतर में चल सकते हैं। " –

उत्तर

10

संक्षिप्त उत्तर: Parallel.ForEach() "सभी धागे को संगठित नहीं करता"। और कोई भी ऑपरेशन जो ThreadPool पर कुछ काम शेड्यूल करता है (जो Parallel.ForEach() करता है) पूल में नए धागे का निर्माण कर सकता है।

लांग जवाब: Parallel.ForEach(), TaskScheduler और ThreadPool:

  1. Parallel.ForEach() (और Parallel.For()) एक TaskScheduler पर उनके काम अनुसूची इस ठीक से समझने के लिए, आप को पता है कि कैसे अमूर्त काम के तीन स्तर की जरूरत है। यदि आप शेड्यूलर को स्पष्ट रूप से निर्दिष्ट नहीं करते हैं, तो the current one का उपयोग किया जाएगा।

    Parallel.ForEach() कई Task एस के बीच काम को विभाजित करता है। प्रत्येक Task इनपुट अनुक्रम के एक हिस्से को संसाधित करेगा, और जब यह हो जाएगा, तो यह उपलब्ध होने पर अन्य भाग का अनुरोध करेगा, और इसी तरह।

    कितने Task एस Parallel.ForEach() बनाएंगे? TaskScheduler जितना अधिक इसे चलाने देगा। जिस तरह से यह किया जाता है यह है कि प्रत्येक Task पहले निष्पादन शुरू होने पर स्वयं की एक प्रति संलग्न करता है (जब तक ऐसा नहीं किया जाता है तो MaxDegreeOfParallelism का उल्लंघन करेगा)। इस तरह, वास्तविक समरूपता स्तर TaskScheduler तक है।

    इसके अलावा, Task वास्तव में वर्तमान थ्रेड पर निष्पादित होगा, अगर TaskScheduler इसका समर्थन करता है (यह RunSynchronously() का उपयोग करके किया जाता है)।

  2. The default TaskScheduler बस ThreadPool कतार में प्रत्येक Task enqueues। (वास्तव में, यह अधिक जटिल है यदि आप किसी अन्य Task से एक Task शुरू करते हैं, लेकिन यह है कि यहां प्रासंगिक नहीं है।) अन्य TaskScheduler रों पूरी तरह से अलग कर सकते हैं और उनमें से कुछ (जैसे TaskScheduler.FromCurrentSynchronizationContext()) Parallel.ForEach() साथ प्रयोग के लिए पूरी तरह से अनुपयुक्त हैं।

  3. ThreadPool किसी भी समय किसी भी समय कितने धागे चलाना चाहिए यह तय करने के लिए काफी जटिल एल्गोरिदम का उपयोग करता है। लेकिन यहां सबसे महत्वपूर्ण बात यह है कि नए कार्य आइटम को निर्धारित करना एक नया धागा बनाने का कारण बन सकता है (हालांकि जरूरी नहीं है)। और क्योंकि Parallel.ForEach() के साथ, हमेशा कुछ आइटम निष्पादित किए जाने के लिए कतारबद्ध होता है, यह धागे की संख्या तय करने के लिए ThreadPool के आंतरिक एल्गोरिदम तक पूरी तरह से होता है।

एकत्र किया गया, यह बहुत ज्यादा है कि कितने धागे एक Parallel.ForEach() द्वारा उपयोग किया जाएगा तय करने के लिए असंभव है, क्योंकि यह कई कारकों का पर निर्भर करता है। दोनों चरम सीमाएं संभव हैं: कि लूप वर्तमान धागे पर पूरी तरह से सिंक्रनाइज़ हो जाएगा और प्रत्येक आइटम अपने स्वयं के, नए बनाए गए धागे पर चलाया जाएगा।

लेकिन आम तौर पर, इष्टतम दक्षता के करीब होना चाहिए और आपको शायद उन सभी विवरणों के बारे में चिंता करने की आवश्यकता नहीं है।

1

समांतर। Foreach नए धागे नहीं बनाता है, न ही यह "सभी धागे को संगठित करता है"। यह थ्रेडपूल से सीमित संख्या में धागे का उपयोग करता है और समानांतर निष्पादन के लिए कार्यों को सबमिट करता है। वर्तमान कार्यान्वयन में डिफ़ॉल्ट प्रति थ्रेड का उपयोग करना है।

+1

यह बस सच नहीं है। यदि समांतर 'फोरेच() 'ब्लॉक के अंदर कोड या लंबे समय तक चलता है, तो कोर की संख्या से अधिक धागे का उपयोग किया जाएगा। – svick

0

समांतर धागे के साथ सौदा नहीं करता है - यह कार्य ढांचे के लिए TASKS शेड्यूल करता है। उसके बाद एक शेड्यूलर होता है और डिफ़ॉल्ट शेड्यूलर थ्रेडपूल पर जाता है। यह एक थू संख्या की संख्या (4.0 से 4.5 में बेहतर) खोजने की कोशिश करेगा और थ्रेडपूल धीरे-धीरे नए धागे को स्पिन कर सकता है।

लेकिन उस parallel.foreach के functoin नहीं है;)

Parallel.ForEach किसी भी नए धागा पैदा करेगा ???

यह कभी नहीं होगा। जैसा कि मैंने कहा - इसमें 1000 foreach है, तो यह कतार 10.000 कार्य, प्वाइंट। यह कार्य फैक्ट्री शेड्यूलर ऐसा करेगा जो इसे करने के लिए प्रोग्राम किया गया है ((आप इसे प्रतिस्थापित कर सकते हैं)। आम तौर पर, डिफ़ॉल्ट - हाँ, धीरे-धीरे नए धागे रीजन के भीतर उगेंगे।

+0

* समानांतर * फॉरएच() '* * * के संग्रह पर * आम तौर पर * n *' कार्य नहीं बनायेगा, जो कि बहुत अक्षम हो सकता है। यह स्रोत संग्रह को विभाजित करता है और केवल 'कार्य' बनाता है क्योंकि 'टास्कशेड्यूलर' इसे चलाने की अनुमति देता है। – svick

1

मुझे लगता है कि आपके पास यह गलत तरीका है। PATTERNS OF PARALLEL PROGRAMMING से आप देखेंगे कि Parallel.ForEach सिर्फ वास्तव में वाक्यात्मक चीनी है।

Parallel.ForEach बड़े पैमाने पर कुछ इस तरह करने के लिए नीचे उबला हुआ है,

for (int p = 0; p < arrayStrings.Count(); p++) 
{ 
    ThreadPool.QueueUserWorkItem(DoSomething(arrayStrings[p]); 
} 

ThreadPool शेड्यूलिंग का ख्याल रखता है। रहे हैं थ्रेडपूल का शेड्यूलर कुछ डिग्री के साथ कैसे व्यवहार करता है, इसके बारे में कुछ उत्कृष्ट लेख I आप रुचि रखते हैं, लेकिन टीपीएल के साथ ऐसा करने के लिए कुछ भी नहीं है।

+1

'नया थ्रेड()' हमेशा एक नया धागा बनाएगा, थ्रेडपूल से एक का उपयोग नहीं करेगा।आपके द्वारा पोस्ट किया गया कोड हमेशा संग्रह में आइटम के रूप में कई धागे बनाएगा। यह किसी भी तरह से समानांतर का प्रतिनिधित्व नहीं करता है। –

+0

@AllonGuralnek आप सही हैं, अपडेट किया गया। –

+1

'समांतर। फॉरएच()' 'थ्रेडपूल' के शीर्ष पर नहीं बनाया गया है, यह 'टास्कशेड्यूलर' के शीर्ष पर बनाया गया है। साथ ही, प्रत्येक 'कार्य' में कोड के बारे में यह बेहतर है, ताकि प्रति आइटम एक 'कार्य' न हो। एक और बात यह है कि आपका कोड अवरुद्ध नहीं होगा, लेकिन समानांतर। फॉरएच() 'करता है। – svick