2010-02-07 7 views
8

यहां संदर्भ है: मैं छोटे programming language called Heron के लिए सी # में एक दुभाषिया लिख ​​रहा हूं, और इसमें कुछ प्राचीन सूची संचालन हैं जिन्हें समानांतर में निष्पादित किया जा सकता है।.NET में लघु गणना के लिए मैं सबसे अधिक प्रभावी ढंग से एकाधिक कोर का लाभ कैसे उठा सकता हूं?

मुझे सामना करने वाली सबसे बड़ी चुनौतियों में से एक है जब भी समांतर ऑपरेशन का सामना करना पड़ता है तो अलग-अलग कोरों में मूल्यांकनकर्ता द्वारा किए गए कार्यों को वितरित करना है। यह एक छोटा या लंबा ऑपरेशन हो सकता है, अग्रिम में निर्धारित करना मुश्किल है।

एक चीज जो मुझे चिंता करने की ज़रूरत नहीं है डेटा को सिंक्रनाइज़ करना है: समानांतर संचालन स्पष्ट रूप से डेटा को संशोधित करने की अनुमति नहीं है।

तो प्राथमिक सवाल मैं है:

  • क्या, सबसे प्रभावी तरीका धागे भर में काम वितरित करने के लिए है, ताकि मैं गारंटी ले सकते हैं कि कंप्यूटर दो कोर भर में काम वितरित करेंगे?

मैं भी एक संबंधित सवाल में रुचि:

  • मोटे तौर पर कितनी देर तक एक ऑपरेशन ले इससे पहले कि हम एक और धागा पर काम को अलग करने की भूमि के ऊपर काबू पाने शुरू कर सकते हैं करना चाहिए?

उत्तर

15

यदि आप समांतर संचालन के साथ बहुत कुछ करना चाहते हैं, तो आप .NET 4.0 से शुरू करना चाहते हैं। यहां Parallel Programming for .Net documentation है। आप start here though चाहते हैं। .NET 4.0 बहु-कोर उपयोग के संदर्भ में बहुत कम जोड़ता है।

वर्तमान 3.5 सीरियल विधि:

for(int i = 0; i < 30000; i++) 
{ 
    doSomething(i); 
} 

नई नेट 4.0 समानांतर विधि:

Parallel.For(0, 30000, (i) => doSomething(i)); 

Parallel.For विधि स्वचालित रूप से उपलब्ध कोर की संख्या के बीच मापता है, आप देख सकते हैं यहां एक त्वरित उदाहरण है आप इसका लाभ उठाने में कितनी तेजी से शुरुआत कर सकते हैं। ढांचे में दर्जनों नए पुस्तकालय हैं, जो आपके धागे/कार्य प्रबंधन जैसे पूर्ण थ्रेड/कार्य प्रबंधन का समर्थन करते हैं (सिंकिंग, रद्दीकरण आदि के लिए सभी पाइपिंग सहित)।

Parallel LINQ (PLINQ), Task Factories, Task Schedulers और कुछ अन्य के लिए पुस्तकालय हैं। संक्षेप में, आपके द्वारा निर्धारित विशिष्ट कार्य के लिए .NET 4.0 के लिए आपके लिए बहुत बड़ा लाभ है, और मैं go ahead and grab the free beta 2 (RC coming soon) और प्रारंभ करना चाहता हूं। (नहीं, मैं माइक्रोसॉफ्ट के लिए काम नहीं करता ... लेकिन शायद ही कभी मैं एक आगामी रिलीज को पूरी तरह से पूरा करने की आवश्यकता देखता हूं, इसलिए मैं आपके लिए .NET 4.0 की अत्यधिक अनुशंसा करता हूं)

+3

यदि आप किसी भी कारण से .NET 4.0 का उपयोग नहीं कर सकते हैं, तो एक नज़र डालें थ्रेडपूल –

+0

यह बहुत बढ़िया सामान है। मैंने वीएस 2010 डाउनलोड किया, और मैंने .NET 4.0 स्थापित किया है। हालांकि मैं सोच रहा हूं कि वीएस 2008 से .NET 4.0 का उपयोग कैसे करें (जिसमें मेरा व्यावसायिक संस्करण है)। – cdiggins

+0

@cdigging - संक्षेप में ... आप नहीं कर सकते, ऐसा लगता है जब वीएस2003 था .Net 1.1, VS2005 .Net 2.0 था, .NET CLR रिलीज़ हमेशा एक नए दृश्य स्टूडियो से बंधे (कम से कम इस बिंदु पर) होते हैं। वीएस 2010 का आरटीएम संस्करण 12 अप्रैल के कारण है, आरसी संस्करण इस महीने कुछ समय से बाहर होना चाहिए। –

5

क्योंकि मैं नहीं चाहता था वीएस 2010 का उपयोग करके विकसित करें, और मैंने पाया कि ThreadPool में कोरों में काम वितरित करने के लिए इष्टतम प्रदर्शन नहीं था (मुझे लगता है क्योंकि यह बहुत सारे धागे को शुरू/बंद कर दिया गया है) मैंने अपना खुद का रोलिंग समाप्त कर दिया। आशा है कि अन्य लोगों को इस उपयोगी पाते हैं:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace HeronEngine 
{ 
    /// <summary> 
    /// Represents a work item. 
    /// </summary> 
    public delegate void Task(); 

    /// <summary> 
    /// This class is intended to efficiently distribute work 
    /// across the number of cores. 
    /// </summary> 
    public static class Parallelizer 
    { 
     /// <summary> 
     /// List of tasks that haven't been yet acquired by a thread 
     /// </summary> 
     static List<Task> allTasks = new List<Task>(); 

     /// <summary> 
     /// List of threads. Should be one per core. 
     /// </summary> 
     static List<Thread> threads = new List<Thread>(); 

     /// <summary> 
     /// When set signals that there is more work to be done 
     /// </summary> 
     static ManualResetEvent signal = new ManualResetEvent(false); 

     /// <summary> 
     /// Used to tell threads to stop working. 
     /// </summary> 
     static bool shuttingDown = false; 

     /// <summary> 
     /// Creates a number of high-priority threads for performing 
     /// work. The hope is that the OS will assign each thread to 
     /// a separate core. 
     /// </summary> 
     /// <param name="cores"></param> 
     public static void Initialize(int cores) 
     { 
      for (int i = 0; i < cores; ++i) 
      { 
       Thread t = new Thread(ThreadMain); 
       // This system is not designed to play well with others 
       t.Priority = ThreadPriority.Highest; 
       threads.Add(t); 
       t.Start(); 
      } 
     } 

     /// <summary> 
     /// Indicates to all threads that there is work 
     /// to be done. 
     /// </summary> 
     public static void ReleaseThreads() 
     { 
      signal.Set(); 
     } 

     /// <summary> 
     /// Used to indicate that there is no more work 
     /// to be done, by unsetting the signal. Note: 
     /// will not work if shutting down. 
     /// </summary> 
     public static void BlockThreads() 
     { 
      if (!shuttingDown) 
       signal.Reset(); 
     } 

     /// <summary> 
     /// Returns any tasks queued up to perform, 
     /// or NULL if there is no work. It will reset 
     /// the global signal effectively blocking all threads 
     /// if there is no more work to be done. 
     /// </summary> 
     /// <returns></returns> 
     public static Task GetTask() 
     { 
      lock (allTasks) 
      { 
       if (allTasks.Count == 0) 
       { 
        BlockThreads(); 
        return null; 
       } 
       Task t = allTasks.Peek(); 
       allTasks.Pop(); 
       return t; 
      } 
     } 

     /// <summary> 
     /// Primary function for each thread 
     /// </summary> 
     public static void ThreadMain() 
     { 
      while (!shuttingDown) 
      { 
       // Wait until work is available 
       signal.WaitOne(); 

       // Get an available task 
       Task task = GetTask(); 

       // Note a task might still be null becaue 
       // another thread might have gotten to it first 
       while (task != null) 
       { 
        // Do the work 
        task(); 

        // Get the next task 
        task = GetTask(); 
       } 
      } 
     } 

     /// <summary> 
     /// Distributes work across a number of threads equivalent to the number 
     /// of cores. All tasks will be run on the available cores. 
     /// </summary> 
     /// <param name="localTasks"></param> 
     public static void DistributeWork(List<Task> localTasks) 
     { 
      // Create a list of handles indicating what the main thread should wait for 
      WaitHandle[] handles = new WaitHandle[localTasks.Count]; 

      lock (allTasks) 
      { 
       // Iterate over the list of localTasks, creating a new task that 
       // will signal when it is done. 
       for (int i = 0; i < localTasks.Count; ++i) 
       { 
        Task t = localTasks[i]; 

        // Create an event used to signal that the task is complete 
        ManualResetEvent e = new ManualResetEvent(false); 

        // Create a new signaling task and add it to the list 
        Task signalingTask =() => { t(); e.Set(); }; 
        allTasks.Add(signalingTask); 

        // Set the corresponding wait handler 
        handles[i] = e; 
       } 
      } 

      // Signal to waiting threads that there is work 
      ReleaseThreads(); 

      // Wait until all of the designated work items are completed. 
      Semaphore.WaitAll(handles); 
     } 

     /// <summary> 
     /// Indicate to the system that the threads should terminate 
     /// and unblock them. 
     /// </summary> 
     public static void CleanUp() 
     { 
      shuttingDown = true; 
      ReleaseThreads(); 
     } 
    }  
} 
+0

क्या आपने बिल्ड-इन थ्रेडपूल के खिलाफ अपने कार्यान्वयन को बेंचमार्क करने का प्रयास किया है? – Jan

+0

हां, लेकिन केवल मेरे काम के संदर्भ में। यह थोड़ा तेज़ प्रतीत होता है, लेकिन मेरे बेंचमार्क पर भरोसा न करें। मैं बहुत पक्षपाती हूँ। – cdiggins

+0

अपने मैन्युअल रीसेट एवेन्ट्स पर कॉल करना सुनिश्चित करें - http://stackoverflow.com/questions/2234128/do-i-need-to-call-close-on-a-manualresetevent –

2

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

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

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