2010-07-26 13 views
5

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

int threadCount = 0;  

for (int i = 0; i < this.Total; i++) 
{ 
     Finished = new ManualResetEvent(false); 
     threadCount = this.ThreadCount; 
     Interlocked.Increment(ref threadCount); 

     FileHandler fh = new FileHandler(finished, sorted[i], this.PicturesFeatures, this.Outcome, this.SiteIds, this.LastId, this.Order, this.ThreadCount); 
     Console.Write(i + " "); 
     ThreadPool.QueueUserWorkItem(new WaitCallback(HandleFile), fh); 
     Console.Write(i + " "); 
     Finished.WaitOne(); 
} 

और HandleFile() के रूप में चला जाता है:

private void HandleFile(object s) 
    {   
     try 
     { 
      //code   
     } 
     finally 
     { 
      if (Interlocked.Decrement(ref threadCount) == 0) 
      { 
       Finished.Set(); 
      } 
     } 
    } 

मैं उन Console.Write डाल दिया

मेरी सी # कोड के लिए एक नमूना के रूप में Workaround for the WaitHandle.WaitAll 64 handle limit? इस्तेमाल करने के बाद मैं के साथ आया गया है यह सोचकर कि यदि कोई प्रक्रिया अधिक है तो यह किसी अन्य ("0 0 1 2 2 1 3 3 ...") के बाद खत्म हो जाएगी, लेकिन यह हमेशा क्रम में है ("0 0 1 1 2 2 3 3 4 4 ... ")

+0

मेरे पास एक टिप्पणी है: क्या आप सुनिश्चित हैं कि आपका कोड फ़ाइल I/O और डेटाबेस संचालन करने के बजाय समय कंप्यूटिंग सामग्री खर्च करता है? अन्यथा, इस तथ्य से अवगत रहें कि समानांतर में चीजें करने से आपके कोड को बहुत तेज़ नहीं किया जा सकता है (यानी, समानांतर में फ़ाइलों को पढ़ने के लिए तेज़ नहीं है कि उन्हें एक-एक करके पढ़ने के लिए; सिवाय इसके कि फ़ाइलों को अलग-अलग हार्ड पर संग्रहीत किया जाता है डिस्क)। –

+0

हां, लेकिन डेटाबेस के बारे में क्या? प्रत्येक थ्रेड डेटाबेस के साथ एक अलग कनेक्शन खोलता है, इसलिए यदि मैं समांतरता का उपयोग करता हूं तो इसे तेज करना चाहिए। –

+0

इतना यकीन नहीं है। परीक्षण करें और देखें कि क्या होता है। सभी मामलों में, यदि बाधा डिस्क I/O संचालन (स्थानीय रूप से या डेटाबेस स्तर पर) है, समानांतरता को लागू करने से चीजों को धीमा कर दिया जाएगा। –

उत्तर

4

आपके आउटपुट की अपेक्षा की जा सकती है। आप मुख्य धागे में आउटपुट लिख रहे हैं, QueueUserWorkItem फ़ंक्शन ब्लॉक नहीं करता है, यह आपके HandleFile फ़ंक्शन को एक अलग थ्रेड में निष्पादित करने के लिए पंजीकृत करता है। तो चाहे काम की वस्तुएं कितनी देर तक ले जाएं, आपके प्रिंट अपेक्षित क्रम में होंगे क्योंकि वे सभी मुख्य धागे से हैं।

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

1

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

उस के साथ कहा, आप प्रोसेस एक्सप्लोरर का उपयोग कर सकते हैं: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx

प्रोसेस एक्सप्लोरर दिखाएगा आप जो अपने कार्यक्रम धागे स्पॉन है।

2

चल रहा है, जबकि निष्पादन में तोड़ें (ctrl + alt + break) और फिर थ्रेड विंडो पर एक नज़र डालें। (डीबग -> विंडोज़ -> थ्रेड)।

+0

ठीक है। मेरे पास मुख्य थ्रेड, के साथ 5 वर्कर थ्रेड हैं, 1 कार्यकर्ता थ्रेड जिसे .NET SystemEvents कहा जाता है, और एक अन्य कार्यकर्ता धागा जिसे vshost.RunParkingWindow कहा जाता है। मैंने कुछ हैलो वर्ल्ड प्रोग्राम की तुलना में तुलना की है, ऐसा लगता है कि बहुत अधिक मल्टीथ्रेडिंग नहीं चल रही है। –

+0

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

2

आपको कुछ समस्याएं हैं।

  • कार्य आइटम प्रभावी रूप से क्रमबद्ध करने जा रहे हैं क्योंकि आप अगली शुरू करने से पहले प्रत्येक को पूरा करने की प्रतीक्षा कर रहे हैं।
  • Console.WriteLine कॉल मुख्य धागे पर हैं, इसलिए उनके लिए i पर क्रमशः वृद्धि के रूप में रिपोर्ट करना स्वाभाविक है।

यह सही तरीके से करने के लिए कैननिकल पैटर्न है।

int count = TOTAL_ITERATIONS; 
var finished = new ManualResetEvent(false); 
for (int i = 0; i < TOTAL_ITERATIONS; i++) 
{ 
    int captured = i; // Use this for variable capturing in the anonymous method. 
    ThreadPool.QueueUserWorkItem(
    delegate(object state) 
    { 
     try 
     { 
     Console.WriteLine(captured.ToString()); 
     // Your task goes here. 
     // Refer to 'captured' instead of 'i' if you need the loop variable. 
     Console.WriteLine(captured.ToString()); 
     } 
     finally 
     { 
     if (Interlocked.Decrement(ref count) == 0) 
     { 
      finished.Set(); 
     } 
     } 
    }); 
} 
finished.WaitOne(); 

संपादित करें: आसानी से प्रदर्शित करने के लिए है कि एक से अधिक थ्रेड उपयोग लागू कर रहे हैं निम्नलिखित कोड।

public static void Main() 
{ 
    const int WORK_ITEMS = 100; 
    int count = WORK_ITEMS; 
    var finished = new ManualResetEvent(false); 
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + ":Begin queuing..."); 
    for (int i = 0; i < WORK_ITEMS; i++) 
    { 
     int captured = i; // Use this for variable capturing in the anonymous method. 
     ThreadPool.QueueUserWorkItem(
      delegate(object state) 
      { 
       try 
       { 
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + ":" + captured.ToString()); 
        for (int j = 0; j < 100; j++) Thread.Sleep(1); 
        Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + ":" + captured.ToString()); 
       } 
       finally 
       { 
        if (Interlocked.Decrement(ref count) == 0) 
        { 
         finished.Set(); 
        } 
       } 
      }); 
    } 
    Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + ":...end queueing"); 
    finished.WaitOne(); 
    Console.ReadLine(); 
} 
+0

मैंने आपके द्वारा प्रस्तावित परिवर्तन किए हैं। तब मैंने थ्रेड विंडो का उपयोग किया (जैसा कि नीचे दिए गए उत्तर पर फिल द्वारा इंगित किया गया है) और, जैसा कि मैंने फिल को बताया था, ऐसा लगता है कि इसका असर नहीं पड़ता है। –

+0

@EduardoMello: ऐसा इसलिए हो सकता है क्योंकि 'थ्रेडपूल' पूल से केवल एक धागे पर क्रमशः कार्य वस्तुओं को निष्पादित करने का चयन कर रहा है। मैंने अपना जवाब उस कोड को शामिल करने के लिए संपादित किया जो इसे काम के सामान को अलग-अलग धागे को सौंपने के लिए मजबूर करता है और दर्शाता है कि यह वास्तव में कंसोल पर थ्रेड आईडी लिखकर ऐसा कर रहा है। –

1

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

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