2013-05-08 13 views
6

मेरे पास एक साधारण प्रोग्राम है जो कुछ मोंटे कार्लो एल्गोरिदम करता है। एल्गोरिदम के साथ एक पुनरावृत्ति दुष्प्रभावों के बिना है, इसलिए मुझे इसे कई धागे से चलाने में सक्षम होना चाहिए।एकाधिक धागे का उपयोग करते समय प्रोग्राम धीमा होता है

void task(unsigned int max_iter, std::vector<unsigned int> *results, std::vector<unsigned int>::iterator iterator) { 
    for (unsigned int n = 0; n < max_iter; ++n) { 
     nume::Album album(535); 
     unsigned int steps = album.fill_up(); 
     *iterator = steps; 
     ++iterator; 
    } 
} 

void aufgabe2() { 
    std::cout << "\nAufgabe 2\n"; 

    unsigned int max_iter = 10000; 

    unsigned int thread_count = 4; 

    std::vector<std::thread> threads(thread_count); 
    std::vector<unsigned int> results(max_iter); 

    std::cout << "Computing with " << thread_count << " threads" << std::endl; 

    int i = 0; 
    for (std::thread &thread: threads) { 
     std::vector<unsigned int>::iterator start = results.begin() + max_iter/thread_count * i; 
     thread = std::thread(task, max_iter/thread_count, &results, start); 
     i++; 
    } 

    for (std::thread &thread: threads) { 
     thread.join(); 
    } 

    std::ofstream out; 
    out.open("out-2a.csv"); 
    for (unsigned int count: results) { 
     out << count << std::endl; 
    } 
    out.close(); 

    std::cout << "Siehe Plot" << std::endl; 
} 

पेचीदा बात यह है कि यह धीमी अधिक धागे मैं जोड़ने हो जाता है: तो यह my whole program के संबंधित भाग, जो सी ++ 11 में लिखा है।

real 0m5.691s 
user 0m3.784s 
sys  0m10.844s 

किसी एकल थ्रेड के साथ जबकि:: 4 धागे के साथ, मैं इस मिल

real 0m1.145s 
user 0m0.816s 
sys  0m0.320s 

मुझे लगता है कि सीपीयू कोर के बीच डेटा ले भूमि के ऊपर जोड़ सकते हैं, लेकिन vector स्टार्टअप पर घोषित किया जाना चाहिए, और बीच में संशोधित नहीं किया जा सकता है। क्या एकाधिक कोर पर धीमा होने का कोई विशेष कारण है?

मेरे प्रणाली एक i5-2550M है, जो 4 कोर (2 + Hyperthreading) है और मैं जी का उपयोग ++ (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3

अद्यतन

मुझे लगता है कि देखा कोई सूत्र का उपयोग कर (1), यह उपयोगकर्ता लोड का एक बहुत होगा, जबकि धागे के साथ (2), यह उपयोगकर्ता लोड से ज्यादा गिरी होगा:

10K चलाता है:

http://wstaw.org/m/2013/05/08/stats3.png

100K चलाता है:

http://wstaw.org/m/2013/05/08/Auswahl_001.png

Current main.cpp

100K रन के साथ, मैं निम्नलिखित मिल:

कोई सूत्र बिल्कुल:

real 0m28.705s 
user 0m28.468s 
sys  0m0.112s 

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

real 2m50.609s 
user 2m45.664s 
sys  4m35.772s 

इसलिए हालांकि तीन मुख्य भागों मेरी सीपीयू की 300% तक का समय लग, वे 6 बार जब तक ले।

1 एम रन के साथ, यह real 4m45 करने के लिए लिया। मैं पहले 1 एम भाग गया, और कम से कम real 20m लिया, अगर real 30m भी नहीं।

+1

'10000' वास्तव में छोटा है ... एक बड़ी संख्या का प्रयास करें। – UmNyobe

+2

शायद संदर्भ स्विच ओवरहेड कार्य को पूरा करने के लिए आवश्यक समय पर हावी है। जैसा कि सुझाव दिया गया है, उस '10000' पर कुछ शून्य जोड़ें ... –

+1

धागे बनाना भी ओवरहेड है। कार्य को एक सरल 'वापसी' करने दें और देखें कि उनमें से कितनी संख्या वास्तविक गणना थी। धागे को बिल्कुल भी बनाने की कोशिश न करें (केवल कार्य फ़ंक्शन को वर्तमान से चलाएं), इसे और भी तेज होना चाहिए। थ्रेड लॉन्च करने के लिए ओएस को क्या करना है, इसकी तुलना में 10 के पुनरावृत्तियों शायद कुछ भी नहीं हैं। – hamstergene

उत्तर

5

गिटहब पर आपके वर्तमान main.cpp का मूल्यांकन किया। ऊपर दी गई टिप्पणी के अलावा:)

  1. हाँ, रैंड (थ्रेड-सुरक्षित तो वहाँ अपनी बहु सूत्रण व्यापार तर्क (कि जिस तरह से चलाने से पहले यादृच्छिक मूल्यों के साथ कुछ सरणी पहले से भरना के लायक हो सकता है, आप नहीं है संभावित ताले की मात्रा घटाना)। यदि आप कुछ ढेर गतिविधि करने की योजना बनाते हैं तो स्मृति आवंटन के बारे में वही (मल्टीथ्रेडिंग से पहले प्री-आवंटन करें या कस्टम प्रति-थ्रेड आवंटक का उपयोग करें)।
  2. अन्य प्रक्रियाओं के बारे में मत भूलना। यदि आप 4 कोर पर 4 धागे का उपयोग करने की योजना बना रहे हैं, तो इसका मतलब है कि आप CPU संसाधनों के लिए अन्य सॉफ़्टवेयर (कम से कम ओएस रूटीन) के साथ प्रतिस्पर्धा करेंगे।
  3. फ़ाइल आउटपुट एक बड़ा लॉकर प्लेयर है। आप "< <" प्रत्येक लूप पुनरावृत्ति पर ऑपरेटर करते हैं और यह आपको बहुत अधिक खर्च करता है (मुझे अपने अतीत में एक मजाकिया मामला याद है: एक लॉग आउटपुट को एक बहु-थ्रेडिंग बग, परोक्ष रूप से तय करना। क्योंकि जेनेरिक लॉगर लॉक-संचालित है, यह है किसी प्रकार का सिंक आदिम, जागरूक रहें!)।
  4. अंत में, कोई भी वारंटी नहीं है कि बहु-थ्रेडेड ऐप सिंगल-थ्रेड से तेज हो सकता है। सीपीयू-विशिष्ट, पर्यावरण-विशिष्ट, आदि पहलुओं का एक गुच्छा है।
1

वेक्टर ऑब्जेक्ट परिणाम सभी धागे द्वारा साझा किए जाते हैं, भले ही आपकी समस्या एक शर्मनाक समानांतर है, साझा वस्तु के कारण, कैश मिस का उल्लेख नहीं करने के लिए एक विवाद है (मैं पर्याप्त नहीं हूं आधुनिक वास्तुकला पर कैश के बारे में समझाओ)। शायद आपके पास अपने एन धागे के लिए एन परिणाम वैक्टर होना चाहिए और अंत में परिणाम मर्ज करना चाहिए। यह अनुमान लगाएगा, मुझे लगता है।

उल्लेख करने के लिए एक और युक्ति थ्रेड के बजाय जब भी संभव हो std :: async का उपयोग करें। यह थ्रेड आवंटन और अन्य निम्न स्तर की गड़बड़ी को संभालता है। मैंने इसे स्कॉट मेयर की प्रभावी सी ++ 11 पुस्तक से पढ़ा। हालांकि, धागे का उपयोग करके, आप थ्रेड एफ़िनिटी को विशेष कोर पर सेट कर सकते हैं। इसलिए, यदि आपका प्रोसेसर 8 धागे का समर्थन करता है, तो आप 8 थ्रेड बना सकते हैं और कम से कम लिनक्स पर प्रत्येक कोर को प्रत्येक थ्रेड असाइन कर सकते हैं।

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

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