2012-07-15 11 views
5
  • मुझे एक I/O गहन ऑपरेशन मिला है।
  • मैं केवल एक बार में अधिकतम 5 धागे चलाना चाहता हूं।
  • मुझे कतार और पूर्ण करने के लिए 8000 कार्य मिल गए हैं।
  • प्रत्येक कार्य निष्पादित करने के लिए लगभग 15-20seconds लेता है।

मैं चारों ओर ThreadPool को देखा है, लेकिनथ्रेडपूल निराशा - सेटमैक्स थ्रेड्स से अधिक थ्रेड निर्माण

 ThreadPool.SetMaxThreads(5, 0); 

     List<task> tasks = GetTasks(); 

     int toProcess = tasks.Count; 
     ManualResetEvent resetEvent = new ManualResetEvent(false); 

     for (int i = 0; i < tasks.Count; i++) 
     { 
      ReportGenerator worker = new ReportGenerator(tasks[i].Code, id); 
      ThreadPool.QueueUserWorkItem(x => 
      { 
       worker.Go(); 
       if (Interlocked.Decrement(ref toProcess) == 0) 
        resetEvent.Set(); 
      }); 
     } 

     resetEvent.WaitOne(); 

मैं समझ नहीं क्यों ... मेरे कोड एक समय में अधिक से अधिक 5 धागे को क्रियान्वित कर रहा है। मैंने setmaxthreads, setminthreads को करने का प्रयास किया है, लेकिन यह 5 से अधिक धागे निष्पादित करता रहता है।

क्या हो रहा है? मैं क्या खो रहा हूँ? क्या मुझे इसे किसी अन्य तरीके से करना चाहिए?

धन्यवाद

+0

आपने डीबगर में ** tasks.Count ** का मान सत्यापित किया है? क्या आपने इसके बजाए बस "5" डालने की कोशिश की है? –

+0

कार्य सरणी में ~ 8000 ऑब्जेक्ट्स हैं – Mike

उत्तर

3

टास्क समानांतर लाइब्रेरी आप मदद कर सकते हैं:

List<task> tasks = GetTasks(); 

Parallel.ForEach(tasks, new ParallelOptions { MaxDegreeOfParallelism = 5 }, 
    task => {ReportGenerator worker = new ReportGenerator(task.Code, id); 
      worker.Go();}); 

What does MaxDegreeOfParallelism do?

+0

यह इतना आसान है! और एक आकर्षण की तरह काम किया! धन्यवाद! – Mike

1

मुझे लगता है कि इस दृष्टिकोण के लिए एक अलग और बेहतर तरीका है। (मुझे माफ़ कर दो अगर मैं गलती से कुछ सिंटैक्स जावा-ize)

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

पहली बात यह है कि सूची में पॉइंटर के रूप में उपयोग के लिए यह कोड क्लास में एक वैरिएबल जोड़ता है। हम अधिकतम वांछित थ्रेड गिनती के लिए भी एक जोड़ देंगे।

// New variable in your class definition 
private int taskStackPointer; 
private final static int MAX_THREADS = 5; 

एक ऐसी विधि बनाएं जो सूची में अगला कार्य लौटाती है और स्टैक पॉइंटर को बढ़ाती है। फिर इस के लिए एक नया इंटरफ़ेस बनाने:

// Make sure that only one thread has access at a time 
[MethodImpl(MethodImplOptions.Synchronized)] 
public task getNextTask() 
{ 
    if(taskStackPointer < tasks.Count) 
     return tasks[taskStackPointer++]; 
    else 
     return null; 
} 

वैकल्पिक रूप से, आप कार्यों लौट सकते हैं [taskStackPointer ++] कोड है, वहाँ एक मूल्य आप "सूची के अंत" अर्थ के रूप में नामित कर सकते हैं अगर।। हालांकि, इसे इस तरह से करना आसान है।

इंटरफ़ेस:

public interface TaskDispatcher 
{ 
    [MethodImpl(MethodImplOptions.Synchronized)] public task getNextTask(); 
} 

ReportGenerator वर्ग के भीतर, निर्माता बदल डिस्पैचर वस्तु स्वीकार करने के लिए:

public ReportGenerator(TaskDispatcher td, int idCode) 
{ 
    ... 
} 

तुम भी ReportGenerator वर्ग इतना है कि परिवर्तन करने के लिए की आवश्यकता होगी प्रसंस्करण में एक बाहरी लूप होता है जो td.getNextTask() पर एक नया कार्य अनुरोध करने के लिए कॉल करके शुरू होता है, और जब यह एक नल वापस आता है तो लूप से बाहर निकलता है।

अंत में, कुछ इस तरह करने के लिए धागा निर्माण कोड में कोई बदलाव: इस तरह आप धागे की वांछित संख्या बनाने

taskStackPointer = 0; 
for (int i = 0; i < MAX_THREADS; i++) 
{ 
    ReportGenerator worker = new ReportGenerator(this,id); 
    worker.Go(); 
} 

और उन सब अधिकतम क्षमता पर कार्य करते रहना (यह सिर्फ एक विचार दे रहा है) ।

(मुझे यकीन नहीं है कि मुझे "[MethodImpl (MethodImplOptions.Synchronized)] का उपयोग मिला है" बिल्कुल सही ...मैं से सी #) जावा के लिए अधिक इस्तेमाल कर रहा हूँ

+0

मेरे प्रश्न का उत्तर देने के लिए समय निकालने के लिए धन्यवाद, यह समझ में आता है। यह विधि अधिक वर्बोज़ है हालांकि: पी – Mike

+0

यह थोड़ा और वर्बोज़ हो सकता है लेकिन एक बार जब आप इसे जगह में ले लेते हैं तो यह बहुत ही कुशल और समझने में आसान होता है। –

1

आपके कार्य सूची में 8k आइटम होंगे, क्योंकि उन पर वहाँ डाल करने के लिए कोड को बताया :

List<task> tasks = GetTasks(); 

कहा कि, इस संख्या के साथ कोई संबंध नहीं है कि कितने धागे अर्थ में प्रयोग किया जा रहा है कि डिबगर हमेशा कितने आइटम आप विज्ञापन दिखाने के लिए जा रहा है सूची में समर्पित

यह निर्धारित करने के कई तरीके हैं कि कितने धागे उपयोग में हैं। शायद सबसे आसान बात यह है कि डीबगर के साथ एप्लिकेशन में तोड़ना और थ्रेड्स विंडो पर नज़र डालना है। न केवल आपको एक गिनती मिलेगी, लेकिन आप देखेंगे कि प्रत्येक थ्रेड क्या कर रहा है (या नहीं) जो मुझे ले जाता है ...

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

अब अपने विशिष्ट सवाल का जवाब देने ...

स्पष्ट रूप से, समवर्ती कार्यों की संख्या को नियंत्रित एक छोटी सी कार्यान्वयन कि BlockingCollection करने के लिए एक सूची से अपने कार्य को संग्रह बदलते शामिल होगा (कि आंतरिक रूप से एक ConcurrentQueue उपयोग किया जाएगा) पर विचार करने के और निम्नलिखित कोड 'उपभोग' के लिए काम करते हैं:

var parallelOptions = new ParallelOptions 
{ 
    MaxDegreeOfParallelism = 5 
}; 

Parallel.ForEach(collection.GetConsumingEnumerable(), options, x => 
{ 
    // Do work here... 
}); 

MaxDegreeOfParallelism बदलें जो कुछ भी करने के लिए समवर्ती मूल्य आप निर्धारित किया है काम आप कर रहे हैं के लिए उपयुक्त है।

आपकी रुचि का हो सकता है निम्नलिखित:

Parallel.ForEach Method

BlockingCollection

क्रिस

3

कि में SetMaxThreads में एक सीमा आप इसे की संख्या की तुलना में कम सेट नहीं कर सकते है सिस्टम पर प्रोसेसर। यदि आपके पास 8 प्रोसेसर हैं, तो इसे 5 पर सेट करना वही है जो फ़ंक्शन को कॉल नहीं कर रहा है।