2015-10-26 65 views
10

比方說,我有兩種方法:爲什麼PLINQ比循環慢?

public BigInteger PFactorial(int n) 
{ 
    return Enumerable.Range(1, n) 
        .AsParallel() 
        .Select(i => (BigInteger)i) 
        .Aggregate(BigInteger.One, BigInteger.Multiply); 
} 

public BigInteger Factorial(int n) 
{ 
    BigInteger result = BigInteger.One; 
    for(int i = 1; i <= n; i++) 
     result *= i; 
    return result; 
} 

下面是結果我:

PFactorial(25000) -> 0,9897 seconds 
Factorial(25000) -> 0,9252 seconds 

據我所知,PLINQ有,因爲線程設置的一些開銷,但這麼大的我期待PLINQ更快。

這裏是另外一個結果是:

PFactorial(50000) -> 4,91035 seconds 
Factorial(50000) -> 4,40056 seconds 
+4

這就是爲什麼我們的標杆。不要猜測並行化某件事會獲得多少收益,而應該測試一下,所以你肯定知道。當然,請記住,聚合可以並行,但並不像其他類型的操作(如預測)那樣有效。 – Servy

+3

'Aggregate'不會並行發生。 – Ryan

+0

'Enumerable.Range'也會造成一些額外的時間... –

回答

10

並行是不是真的有可能與彙總。至少我無法想象在我的腦海裏。任何方式,您應該通過將列表分成塊來實現並行化。找到那些結果。最後再乘以大塊。這是PLinq的快速方法。

static public BigInteger PFactorial(int n) 
{ 
    var range = Enumerable.Range(1, n).Select(x => (BigInteger) x).AsParallel(); 
    var lists = range.GroupBy(x => x/(n/Environment.ProcessorCount)).Select(x => x.AsEnumerable()); 
    var results = lists.Select(x => x.Aggregate(BigInteger.One, BigInteger.Multiply)); 
    var result = results.Aggregate(BigInteger.One, BigInteger.Multiply); 
    return result; 
} 

測試

PFactorial(50000) -> 1,41 seconds 
Factorial(50000) -> 2,69 seconds 

編輯:由於Servy和Chatzigiannakis提到的,如果你不使用它的種子可以完美使用並行,你會得到幾乎相同的結果如上(快一點)。

return Enumerable.Range(1,n).Select(x => (BigInteger)x).AsParallel().Aggregate(BigInteger.Multiply); 
+1

'Aggregate'''絕對可以並行執行它的工作,而不是在有種子的時候。當然,它的工作方式與您所做的完全一致,即將工作分解爲塊,並行彙總,然後梳理中間結果。 – Servy

+0

我嘗試過不使用種子。我仍然得到與正常階乘相同的結果。任何方式感謝信息。我看着它。 @Servy –

+1

'ParallelEnumerable.Aggregate'在內部區分關聯和非關聯聚合函數,並行運行前者。當沒有說明時,我認爲它假設了聯想(和交換)。 –

1

請不要以爲pLinQ總是比LinQ快。基於許多條件的PLinQ執行時間

只有當有更多元素並且有一些CPU密集型查詢時才使用PLinQ。我建議在函數中使用System.Threading.Thread.Sleep(1)來模擬CPU負載作爲週期延遲,然後從LinQ和PlinQ調用該函數10000次。然後你可以看到差異。請發現sample here

您當前的函數因爲實際上沒有執行任何CPU密集型任務和原因PLinQ需要更多的時間,因爲它會使查詢在多個核心中運行,並將單個核心的結果合併到單個輸出中,時間然後正常。

還要確保您使用的是多核心處理器(最低4會給你很好的分析)

+0

*「您當前的函數Factorial實際上沒有執行任何CPU密集型任務」*是的,是的。 – Ryan

+0

@minitech它不是 - 它只是將一些數字相乘,看起來平均(4900ms/50000)0.098ms乘法。爲了實現任何收益,特別是要考慮所有工作,以確定批量,啓動線程,處理所有包裝等,這不是一項偉大的任務。 – NPSF3000

+2

@ NPSF3000:經公認的答案證明,它可以實現收益。 – Ryan

相關問題