2008-08-28 10 views
50

मान लीजिए कि मेरे पास सी # में एक प्रोग्राम था जिसने एमपी 3 में डब्ल्यूएवी फाइलों की सूची एन्कोड करने की तरह कुछ कम्प्यूटेशनल रूप से महंगा किया था। आम तौर पर मैं एक समय में फ़ाइलों को एन्कोड करता हूं, लेकिन मान लें कि मैं चाहता हूं कि प्रोग्राम यह पता लगाए कि कितने सीपीयू कोर हैं और प्रत्येक कोर पर एन्कोडिंग थ्रेड स्पिन करें। इसलिए, जब मैं क्वाड कोर सीपीयू पर प्रोग्राम चलाता हूं, तो प्रोग्राम के आंकड़े बताते हैं कि यह क्वाड कोर सीपीयू है, इसके साथ काम करने के लिए चार कोर हैं, फिर एन्कोडिंग के लिए चार थ्रेड स्पंज करते हैं, जिनमें से प्रत्येक अपने अलग से चल रहा है सी पी यू। यह मैं कैसे करूंगा?मैं अलग-अलग CPU कोर पर थ्रेड कैसे बढ़ा सकता हूं?

और यदि यह एकाधिक भौतिक CPUs में कोर फैल गया तो यह अलग होगा? जैसा कि, अगर मेरे पास दो क्वाड कोर सीपीयू के साथ एक मशीन थी, तो क्या कोई विशेष विचार है या क्या दो कोरों में आठ कोर हैं जो विंडोज में बराबर मानते हैं?

उत्तर

51

ऐसा करने से परेशान मत हो।

इसके बजाय Thread Pool का उपयोग करें। थ्रेड पूल ढांचे का एक तंत्र (वास्तव में एक वर्ग) है जिसे आप एक नए धागे के लिए पूछ सकते हैं।

जब आप एक नया धागा मांगते हैं तो यह आपको एक नया धागा देगा या जब तक धागा मुक्त नहीं हो जाता है तब तक काम को एनक्यूयू करेगा। इस तरह ढांचे को तय करने पर ढांचा प्रभारी होता है, इसे मौजूदा धागे की संख्या के आधार पर अधिक धागे बनाना चाहिए या नहीं।

संपादित करें: इसके अतिरिक्त, जैसा कि पहले से ही उल्लेख किया गया है, ओएस विभिन्न CPUs के बीच धागे को वितरित करने का प्रभारी है।

+1

क्या आप हेवन अगर ' नहीं मिला .NET? – Crashworks

+52

यह एक .NET संबंधित प्रश्न है। आपके पास .NET क्यों नहीं होगा? –

+0

टीपीएल (टास्क समांतर) को शामिल करने के लिए और भी यह काम लेता है आप यहां और अधिक पढ़ सकते हैं http://msdn.microsoft.com/en-us/magazine/cc163340.aspx –

1

जहां प्रत्येक थ्रेड आमतौर पर ओएस द्वारा संभाला जाता है ... तो 4 कोर सिस्टम पर 4 धागे उत्पन्न करें और ओएस तय करेगा कि कौन से कोर प्रत्येक को चलाने के लिए, जो आमतौर पर प्रत्येक कोर पर 1 धागा होगा।

1

यह विभिन्न कोरों में धागे को विभाजित करने के लिए ऑपरेटिंग सिस्टम का काम है, और यह तब होगा जब आपके थ्रेड बहुत सी CPU समय का उपयोग कर रहे हों। इसके बारे में चिंता मत करो। यह पता लगाने के लिए कि आपके उपयोगकर्ता के कितने कोर हैं, सी # में Environment.ProcessorCount आज़माएं।

2

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

1

आपके द्वारा इस तरह की चीजों को आवंटित करने के कारणों में से एक कारण यह नहीं है कि आपके पास यह ठीक से करने के लिए पर्याप्त जानकारी नहीं है, खासकर भविष्य में NUMA, आदि के साथ।

यदि आपके पास थ्रेड रीड-टू-रन है, और कोर निष्क्रिय है, तो कर्नेल आपके थ्रेड को चलाएगा, चिंता न करें।

8

प्रबंधित धागे के मामले में, ऐसा करने की जटिलता देशी धागे की तुलना में एक डिग्री अधिक है। ऐसा इसलिए है क्योंकि सीएलआर धागे सीधे देशी ओएस थ्रेड से बंधे नहीं होते हैं। दूसरे शब्दों में, सीएलआर प्रबंधित धागे को मूल धागे से मूल धागे में बदल सकता है क्योंकि यह फिट दिखाई देता है। फ़ंक्शन Thread.BeginThreadAffinity को मूल ओएस थ्रेड के साथ लॉक-चरण में प्रबंधित थ्रेड रखने के लिए प्रदान किया जाता है। उस बिंदु पर, आप अंतर्निहित मूल थ्रेड प्रोसेसर एफ़िनिटी देने के लिए देशी एपीआई का उपयोग करके प्रयोग कर सकते हैं। जैसा कि हर कोई यहां सुझाता है, यह एक बहुत अच्छा विचार नहीं है। वास्तव में documentation यह सुझाव देता है कि थ्रेड को प्रोसेसर या कोर तक सीमित होने पर कम प्रोसेसिंग समय प्राप्त हो सकता है।

आप System.Diagnostics.Process कक्षा का भी पता लगा सकते हैं। वहां आप ProcessThread ऑब्जेक्ट्स के संग्रह के रूप में एक प्रक्रिया 'थ्रेड को गिनने के लिए एक फ़ंक्शन पा सकते हैं।इस वर्ग ProcessorAffinity स्थापित करने के लिए विधियां या यहां तक ​​कि सेट एक वरीय प्रोसेसर - यकीन नहीं है कि क्या है।

अस्वीकरण: मुझे एक ऐसी ही समस्या का अनुभव हुआ है जहां मैंने सोचा था कि सीपीयू का उपयोग किया गया था और इस सामग्री का बहुत से शोध किया गया था; हालांकि, वह सब मैंने पढ़ा है पर आधारित है, ऐसा लगता है कि एक बहुत अच्छा विचार है, के रूप में टिप्पणी यहाँ भी पोस्ट इसका सबूत नहीं था। हालांकि, यह अभी भी दिलचस्प है और प्रयोग करने के लिए एक सीखने का अनुभव है।

17

यह जरूरी थ्रेड पूल का उपयोग कर के रूप में सरल नहीं है।

डिफ़ॉल्ट रूप से, थ्रेड पूल प्रत्येक सीपीयू के लिए एकाधिक धागे आवंटित करता है। चूंकि हर धागा जो काम आप कर रहे हैं में शामिल हो जाता है एक लागत है (कार्य भूमि के ऊपर स्विचन, CPU के बहुत सीमित एल 1, एल 2 और शायद L3 कैश, आदि ... का उपयोग), का उपयोग करने के धागे की इष्टतम संख्या < है = उपलब्ध सीपीयू की संख्या - जब तक कि प्रत्येक थ्रेड अन्य मशीनों से सेवाओं का अनुरोध नहीं कर रहा है - जैसे उच्च स्केलेबल वेब सेवा। कुछ मामलों में, विशेष रूप से उन जो अधिक हार्ड डिस्क पढ़ने और सीपीयू गतिविधि की तुलना में लेखन शामिल है, तो आप वास्तव में एक से अधिक थ्रेड से कम 1 धागे से बेहतर हो सकता है।

अधिकांश अनुप्रयोगों के लिए, और निश्चित रूप से डब्ल्यूएवी और एमपी 3 एन्कोडिंग के लिए, आपको उपलब्ध सीपीयू की संख्या में कार्यकर्ता धागे की संख्या सीमित करनी चाहिए। यहाँ कुछ सी # CPU के की संख्या को खोजने के लिए कोड है:

int processors = 1; 
string processorsStr = System.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS"); 
if (processorsStr != null) 
    processors = int.Parse(processorsStr); 

दुर्भाग्य से, यह CPU के की संख्या अपने आप को सीमित करने के रूप में सरल नहीं है। आपको हार्ड डिस्क नियंत्रक (डिस्क) और डिस्क (ओं) के प्रदर्शन को भी ध्यान में रखना होगा।

एकमात्र तरीका है कि आप वास्तव में थ्रेड की इष्टतम संख्या पा सकते हैं एक त्रुटि है। यह विशेष रूप से सच है जब आप हार्ड डिस्क, वेब सेवाओं और ऐसे का उपयोग कर रहे हैं। हार्ड डिस्क के साथ, आप क्वाड प्रोसेसर सीपीयू पर सभी चार प्रोसेसर का उपयोग न करने से बेहतर हो सकते हैं। दूसरी ओर, कुछ वेब सेवाओं के साथ, आप प्रति CPU 10 या 100 अनुरोधों को बंद करने से बेहतर हो सकते हैं।

+3

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

1

यदि आप ऐसा नहीं कर सकते हैं, के रूप में केवल ऑपरेटिंग सिस्टम विशेषाधिकार यह करने के लिए है। यदि आप इसे तय करेंगे ..... तो अनुप्रयोगों को कोड करना मुश्किल होगा। क्योंकि तब आपको इंटर-प्रोसेसर संचार की भी देखभाल करने की आवश्यकता है। महत्वपूर्ण वर्ग प्रत्येक एप्लिकेशन के लिए आपको अपना स्वयं का सेमफोर या म्यूटेक्स बनाना होगा ...... जिस ऑपरेटिंग सिस्टम ने इसे स्वयं कर कर एक सामान्य समाधान दिया है .......

2

आप नियमित रूप से दिनचर्या लिखकर ऐसा कर सकते हैं अपने कार्यक्रम के अंदर

हालांकि आपको ऐसा करने की कोशिश नहीं करनी चाहिए, क्योंकि इन सामग्री का प्रबंधन करने के लिए ऑपरेटिंग सिस्टम सबसे अच्छा उम्मीदवार है। मेरा मतलब है कि उपयोगकर्ता मोड प्रोग्राम को ऐसा करने की कोशिश नहीं करनी चाहिए।

हालांकि, कभी-कभी, लोड संतुलन प्राप्त करने के लिए और वास्तव में वास्तविक बहु थ्रेड मल्टी कोर समस्या (डेटा रेसिंग/कैश समेकन ...) को खोजने के लिए भी किया जा सकता है क्योंकि विभिन्न धागे वास्तव में होंगे विभिन्न प्रोसेसर पर निष्पादन।

यह कहकर कि, यदि आप अभी भी हासिल करना चाहते हैं तो हम इसे निम्न तरीके से कर सकते हैं। मैं आपको (विंडोज ओएस) के लिए छद्म कोड प्रदान कर रहा हूं, हालांकि वे आसानी से लिनक्स पर भी किए जा सकते हैं।

#define MAX_CORE 256 
processor_mask[MAX_CORE] = {0}; 
core_number = 0; 

Call GetLogicalProcessorInformation(); 
// From Here we calculate the core_number and also we populate the process_mask[] array 
// which would be used later on to set to run different threads on different CORES. 


for(j = 0; j < THREAD_POOL_SIZE; j++) 
Call SetThreadAffinityMask(hThread[j],processor_mask[j]); 
//hThread is the array of handles of thread. 
//Now if your number of threads are higher than the actual number of cores, 
// you can use reset the counters(j) once you reach to the "core_number". 

के बाद ऊपर दिनचर्या कहा जाता है, धागे हमेशा निम्नलिखित तरीके से क्रियान्वित किया जाएगा:

Thread1-> Core1 
Thread2-> Core2 
Thread3-> Core3 
Thread4-> Core4 
Thread5-> Core5 
Thread6-> Core6 
Thread7-> Core7 
Thread8-> Core8 

Thread9-> Core1 
Thread10-> Core2 
............... 

अधिक जानकारी के लिए मैनुअल को देखें/MSDN इन अवधारणाओं के बारे में अधिक पता करने के लिए।

1

हालांकि मैं यहां अधिकतर उत्तर से सहमत हैं, मुझे लगता है कि यह एक नया विचार जोड़ने के लिए इसके लायक है: स्पीडस्टेप टेक्नोलॉजी।

एक बहु-कोर सिस्टम पर एक सीपीयू गहन, सिंगल थ्रेडेड जॉब चलाने पर, मेरे मामले में विंडोज सर्वर 2012 के तहत 6 असली कोर (एचटी के साथ 12) के साथ एक ज़ीऑन ई 5-2430, नौकरी सभी के बीच फैल गई 12 कोर, प्रत्येक कोर के लगभग 8.33% का उपयोग करते हुए और कभी भी गति वृद्धि को ट्रिगर नहीं करते हैं। सीपीयू 1.2 गीगाहर्ट्ज पर बना रहा।

जब मैं एक विशिष्ट कोर के लिए धागा आत्मीयता निर्धारित करते हैं, यह है कि कोर के लिए प्रयोग किया जाता ~ 100%, 2.5 GHz पर अधिकतम करने के लिए सीपीयू बाहर के कारण, प्रदर्शन दुगुने से अधिक।

इस कार्यक्रम मैं प्रयोग किया जाता है, जो सिर्फ एक चर बढ़ती छोरों है। जब -ए के साथ बुलाया जाता है, तो यह एफ़िनिटी को कोर 1 पर सेट करेगा। एफ़िनिटी भाग this post पर आधारित था।

using System; 
using System.Diagnostics; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Threading; 

namespace Esquenta 
{ 
    class Program 
    { 
     private static int numThreads = 1; 
     static bool affinity = false; 
     static void Main(string[] args) 
     { 
      if (args.Contains("-a")) 
      { 
       affinity = true; 
      } 
      if (args.Length < 1 || !int.TryParse(args[0], out numThreads)) 
      { 
       numThreads = 1; 
      } 
      Console.WriteLine("numThreads:" + numThreads); 
      for (int j = 0; j < numThreads; j++) 
      { 
       var param = new ParameterizedThreadStart(EsquentaP); 
       var thread = new Thread(param); 
       thread.Start(j); 
      } 

     } 

     static void EsquentaP(object numero_obj) 
     { 
      int i = 0; 
      DateTime ultimo = DateTime.Now; 
      if(affinity) 
      { 
       Thread.BeginThreadAffinity(); 
       CurrentThread.ProcessorAffinity = new IntPtr(1); 
      } 
      try 
      { 
       while (true) 
       { 
        i++; 
        if (i == int.MaxValue) 
        { 
         i = 0; 
         var lps = int.MaxValue/(DateTime.Now - ultimo).TotalSeconds/1000000; 
         Console.WriteLine("Thread " + numero_obj + " " + lps.ToString("0.000") + " M loops/s"); 
         ultimo = DateTime.Now; 
        } 
       } 
      } 
      finally 
      { 
       Thread.EndThreadAffinity(); 
      } 
     } 

     [DllImport("kernel32.dll")] 
     public static extern int GetCurrentThreadId(); 

     [DllImport("kernel32.dll")] 
     public static extern int GetCurrentProcessorNumber(); 
     private static ProcessThread CurrentThread 
     { 
      get 
      { 
       int id = GetCurrentThreadId(); 
       return Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Single(x => x.Id == id); 
      } 
     } 
    } 
} 

और परिणाम:

results

प्रोसेसर गति, के रूप में कार्य प्रबंधक द्वारा दिखाया गया है, इसी तरह क्या सीपीयू-जेड की रिपोर्ट के:

enter image description here

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