2012-06-06 11 views
5

से तेज क्यों है, मैंने PLINQ के साथ स्वयं को परिचित करने के लिए कुछ बुनियादी नमूना कोड लिखा था।मेरे असाइन किए गए PLINQ क्वेरी को मेरे अनियंत्रित एक

मैं कुछ अजीब में आया था। मुझे नहीं पता कि यह मेरे कोड में एक त्रुटि है या PLINQ की मेरी समझ में एक त्रुटि है।

एमएसडीएन दस्तावेज बताता है कि AsOrdered() जोड़ना प्रदर्शन की संभावित लागत पर कॉल के आदेश को सुरक्षित रखेगा।

मैंने कुछ यूनिट परीक्षण लिखे और दस्तावेज में बताए गए परिणाम सेट पर आदेश पर प्रभाव देखा। लेकिन मैंने प्रदर्शन पर प्रतिकूल प्रभाव देखा है।

public IEnumerable<int> ParallelCalculatePrimesUpTo(int maxValue) 
{ 
    return from number in Enumerable.Range(1, maxValue).AsParallel() 
      where IsPrime(number) 
      select number; 
} 

public IEnumerable<int> OrderedParallelCalculatePrimesUpTo(int maxValue) 
{ 
    return from number in Enumerable.Range(1, maxValue).AsParallel().AsOrdered() 
      where IsPrime(number) 
      select number; 
} 

और मेरे बहुत ही सरल मानक

[TestMethod] 
    public void SimplisticBenchmark6() 
    { 
     var primeNumberCalculator = new PrimeNumberCalculator(); 

     var startTime = DateTime.Now; 

     primeNumberCalculator.ParallelCalculatePrimesUpTo(10000000).ToList(); 

     var totalTime = DateTime.Now - startTime; 

     Console.WriteLine(totalTime); 
    } 

    [TestMethod] 
    public void SimplisticBenchmark7() 
    { 
     var primeNumberCalculator = new PrimeNumberCalculator(); 

     var startTime = DateTime.Now; 

     primeNumberCalculator.OrderedParallelCalculatePrimesUpTo(10000000).ToList(); 

     var totalTime = DateTime.Now - startTime; 

     Console.WriteLine(totalTime); 
    } 

कोई फर्क नहीं पड़ता कि कितनी बार मैं इस परीक्षण चलाने का आदेश दिया संस्करण अव्यवस्थित एक बाहर धड़कता है:

यहाँ दोनों मेरे तरीका है। मुझे अपने क्वाड कोर कंप्यूटर पर आदेशित एक के लिए लगभग 4 सेकंड तेज मिलता है। मुझे आदेशित एक के लिए लगभग 18 सेकंड और अनियंत्रित के लिए 22 सेकंड मिल रहे हैं। मैंने दो दिनों के दौरान दर्जनों समय परीक्षण किए हैं (उन दिनों के बीच रिबूट के साथ)।

यदि मैं संख्या 10 000 000 से 6 000 000 कम करता हूं, तो अंतर अभी भी वहां है लेकिन कम ध्यान देने योग्य है और यदि मैं इसे 3 000 000 तक कम करता हूं, तो यह एक ही गति के बारे में है।

मैंने निष्पादन के दोनों क्रम में परीक्षण चलाने की कोशिश की और परिणाम समान हैं।

// uses inneficient trial division algorithm 
private bool IsPrime(int number) 
{ 
    if (number == 1) 
     return false; 

    for (int divisor = 2; divisor <= Math.Sqrt(number); divisor++) 
    { 
     if (number % divisor == 0) 
      return false; 
    } 

    return true; 
} 

यह क्या बताते हैं:

यहाँ IsPrime विधि PLINQ क्वेरी में बुलाया जाता है?

+5

एक साइड नोट के रूप में, 'स्टॉपवॉच' का उपयोग करके 'डेटटाइम' प्रदर्शन माप के लिए बहुत अच्छा नहीं है। – svick

+0

@svick: बहुत अच्छा बिंदु। मुझे पता था कि डेटटाइम गंभीर माप के लिए अच्छा नहीं था लेकिन स्टॉपवॉच के बारे में नहीं पता था। धन्यवाद। उत्पादन कोड के लिए एक प्रोफाइलर का उपयोग करना बेहतर होता है, लेकिन यह केवल तेज़ और गंदे कोड था जैसा मैंने लिखा था क्योंकि मैंने PLINQ और TPL दस्तावेज़ पढ़ा था। अगली बार मैं ऐसी स्थिति में स्टॉपवॉच का उपयोग करूंगा! – Gilles

+0

यदि मैं आपका कोड चलाता हूं, तो आदेश दिया गया है कि आदेश थोड़ा धीमा है (5.67 एस बनाम 5.66 एस अनियंत्रित है, कई प्रयासों पर औसत है), लेकिन प्रयासों के बीच भिन्नता आदेशित और अनियंत्रित के बीच के अंतर से अधिक है, इसलिए मुझे लगता है कि कोई नहीं है इस मामले में सांख्यिकीय रूप से महत्वपूर्ण अंतर (कम से कम मेरे क्वाड-कोर पर मापा गया)। – svick

उत्तर

1

क्या आप हमें बता सकते हैं कि सीपीयू उपयोग 4 अलग-अलग कोरों में क्या है? यह संभव है कि AsOrdered() एक ही कोर पर होने वाली अधिक अनुक्रमिक कॉल को मजबूर कर रहा है। बेहतर इलाके के साथ, सिलिकॉन-स्तरीय कैशिंग और शाखा भविष्यवाणी आपके पक्ष में काम कर रही है।

एक और संभावना यह है कि AsOrdered() प्रक्षेपण का उपयोग करते समय monotonically बढ़ते पूर्णांक (int.Range) के मामले में .NET ढांचे में कुछ अनुकूलन है। मुझे यकीन नहीं है कि यह कैसे काम करेगा, लेकिन यह संभव है।

तुलना के लिए एक दिलचस्प परीक्षण यादृच्छिक क्रम में संख्याओं का तीसरा सेट उत्पन्न करना होगा (जाहिर है, आपको उन्हें समय से पहले यादृच्छिक बनाना होगा और फिर तीन सरणी बंद करना होगा)। फिर देखें कि इसका क्या संबंध है?

+0

मुझे दोनों के लिए बहुत कुछ मिल रहा है, यहां: http://gillesleblanc.wordpress.com/?attachment_id=361 विंडोज टास्क मैनेजर से एक तस्वीर है। यह चार कोर है। दोनों परीक्षणों के लिए लगभग 100% की वृद्धि हुई। पहला परीक्षण पहली बार बढ़ रहा है, और दूसरी परीक्षा दूसरी वृद्धि है। – Gilles

+0

ठीक है - मुझे पता है कि वहां इंटेल, एएमडी और अन्य लोगों से कुछ फैंसी टूल्स हैं जो आपको कैशिंग आदि की निगरानी करने देते हैं, लेकिन मुझे विवरणों के बारे में निश्चित नहीं है। सरल विकल्प: मैंने अभी देखा है कि दो परीक्षण अलग [TestMethod] विधियों में चल रहे हैं। क्या आप उन्हें एक एकल [TestMethod] में जोड़ सकते हैं - शायद प्रत्येक ऑर्डरिंग के लिए एक विधि - और इस तरह के ऑर्डर करने के प्रभाव की तुलना करें? फिर आपने कुछ सबसे पुराने पर्यावरणीय कारकों से इंकार कर दिया है। (वास्तव में, सभी तरह से जाएं और इसे एक स्टैंडअलोन कंसोल ऐप के रूप में लिखें। मुझे लगता है कि एमएसटीएस्ट में एक सुविधा है जो रुका हुआ/लटका परीक्षणों की जांच करता है।) –

+0

मैंने एक कंसोल ऐप लिखा है जो दोनों तरीकों को 4 बार निम्नलिखित क्रम में कॉल करता है: अनॉर्डर्ड , आदेश दिया, आदेश दिया, unordered, unordered, आदेश दिया, आदेश दिया, unordered। पहली कॉल के अलावा जो धीमा है, सभी यूनिट कॉल मेरे यूनिट परीक्षणों में मेरे परिणामों के करीब आते हैं। – Gilles

3

क्या आप हमेशा उसी क्रम में टेस्ट चलाते हैं?

मैंने अपनी मशीनों पर अपने परिणाम फिर से बनाए हैं और मैंने पाया कि, 'आदेश' परिणाम तेजी से थे। मैं थोड़ा बेंच मार्किंग के लिए कोड को संशोधित करते थे:

static void Main(string[] args) 
{ 
    const int size = 9000000; 
    BenchIt("Parallel", ParallelCalculatePrimesUpTo, size); 
    BenchIt("Ordered ", OrderedParallelCalculatePrimesUpTo, size); 
    Console.ReadKey(); 
} 

public static void BenchIt(string desc, Func<int, IEnumerable<int>> myFunc, int size) 
{ 
    var sw = new Stopwatch();    
    sw.Restart(); 
    myFunc.Invoke(size).ToList(); 
    sw.Stop(); 
    Console.WriteLine("{0} {1}",desc, sw.Elapsed); 
} 

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

लेकिन - मेरी मशीन पर दोनों के बीच अंतर बहुत छोटे थे। आपने जो अंतर देखा है उसके पास कहीं भी नहीं।

आपका हार्डवेयर कैसा दिखता है?

PLINQ कुछ अनुमान लगाता है कि सबसे तेज़ निष्पादन कैसे करें। मुझे नहीं पता कि यह सीधे इस मामले में आपकी मदद करेगा या नहीं; लेकिन आप IsPrime के बीच में एक ब्रेक पॉइंट सेट करना चाहते हैं और कुछ सौ पुनरावृत्तियों के बाद इसे रोकना और थ्रेड विंडो की जांच करना चाहते हैं।

ParallelCalculatedPrimesUpTo कविता OrderedParallelCalculatePrimesUpTo निष्पादित करते समय आपके पास कितने धागे हैं? मैं यहाँ पहुंच रहा हूँ; लेकिन यह संभव है कि यह आपकी मशीन पर अलग-अलग मूल्यों पर निर्णय ले रहा है जो आपके द्वारा देखे जा रहे अप्रत्याशित समय बनाता है। मेरी मशीन पर - मुझे हर बार आठ धागे मिलते हैं - लेकिन मेरे समय लगभग समान होते हैं - जो भी पहले कहा जाता है वह उन धागे के निर्माण के कारण धीमा होता है। लेकिन आपको किसी विशेष संख्या में धागे की गारंटी नहीं है (आप अधिकतम सेट कर सकते हैं, लेकिन आप उन्हें इस्तेमाल करने के लिए मजबूर नहीं कर सकते हैं)।

+0

पहले प्रश्न के बारे में, मुझे परिणामों में एक ही पैटर्न मिलता है यदि मैं उन्हें किसी भी क्रम में चलाता हूं या यदि मैं उन्हें अलग-अलग परीक्षणों में अलग-अलग चलाता हूं। – Gilles

+0

दूसरे प्रश्न (हार्डवेयर) के बारे में: एएमडी फेनोम 9550 क्वाड-कोर प्रोसेस 2.20 गीगा, 6.00 जीबी रैम, 64 बिट ओएस/सीपीयू, एनवीआईडीआईए जीएफएक्स कार्ड (1 जीबी वीआरएएम), 7200 आरपीएम एचडीडी। – Gilles

+0

अनियंत्रित परीक्षण खिड़की में कुल 14 धागे दिखाता है, लेकिन 2 परीक्षण एजेंट से प्रतीत होता है। आदेश दिया गया एक 16 धागे दिखाता है, लेकिन परीक्षण एजेंट से केवल 2 ही। दोनों मामलों में धागे के अधिकतर मेरे प्रोग्राम या गैर-वर्णनात्मक (मेरी आंखों के लिए) नाम से असंबंधित प्रतीत होते हैं। – Gilles

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