2012-02-07 40 views
2

我遇到過這種情況,使用LINQ工作正常,但PLINQ導致「OutOfMemoryException」。以下是示例代碼使用PLINQ導致OutofMemory異常但不與LINQ一起使用?

static void Main(string[] args) 
    { 
     Stopwatch timer = new Stopwatch(); 

     var guidList = new List<Guid>(); 
     for (int i = 0; i < 10000000; i++) 
     { 
      guidList.Add(Guid.NewGuid()); 
     } 
     timer.Start(); 

     // var groupedList = guidList.GroupBy(f => f).Where(g => g.Count() > 1); 
     var groupedList = guidList.AsParallel().GroupBy(f => f).Where(g => g.Count() > 1); 
     timer.Stop(); 

     Console.WriteLine(string.Format("Took {0} ms time with result: {1} duplications", timer.ElapsedMilliseconds, groupedList.Count())); 
     Console.ReadKey(); 
    } 

拋出內部異常「類型‘System.OutOfMemoryException的’引發的異常」 ..可能是什麼問題?在這種情況下使用PLINQ的準則是什麼,請提前致謝。

+0

GroupBy並不是一個好的選擇。嘗試在羣組之後移動,看​​看是否解決了這個問題。平行的地方很容易做到。 – Rangoric 2012-02-07 17:10:27

+1

我會猜測你得到這個預期的原因是因爲你試圖分配160,000,000字節到內存中。 (GUID是128位即16字節)。如果我沒有弄錯的話,我認爲這會降低到大約16GB。當你使用非並行方法時,代碼是否真的完成了,分配多少內存也應該失敗。 – 2012-02-07 17:15:18

+0

你正在做一切在64位操作系統上的權利? – 2012-02-07 17:15:45

回答

3

您可能接近於在常規Linq版本上耗盡內存,但使用AsParallel()將增加額外的分區開銷以並行運行,並因此超出了限制。

當我嘗試你的示例時,我起初有相同的結果,非並行版本將完成,但PLinq版本將耗盡內存 - 雙倍Guid列表大小,然後導致兩個版本內存不足。還要注意千萬的GUID需要大約152 MB的內存空間

另外請注意,您目前PLINQ和LINQ查詢您的Console.WriteLine()只執行 - 因爲LINQ的是懶惰的,你必須強制評估,即使用ToList()(或你的情況Count()

+0

由於brokenGlass沒有提到它,所以最後一行的分支意味着定時器沒有意義。計數需要在.Stop之前,因爲它意味着什麼。 – Servy 2012-02-07 17:33:54

+0

如果您計算'AsParallel'的成本而不是調用它,這意味着_something_。雖然我敢打賭,這不是意圖。 ;-) – 2012-02-07 17:39:23

2

至少可以緩解問題的一種方法是不將所有的guid放入列表中,而是使用可枚舉。

public IEnumerable<Guid> getGuids(int number) 
{ 
    for (int i = 0; i < number; i++) 
    { 
     yield return Guid.NewGuid(); 
    } 
} 

這有幾個優點。首先,這是懶惰的加載,所以你會在處理過程中失敗,而不是guid的聲明。其次,你沒有堅持所有違反where子句的guid,他們可以從內存中刪除。這意味着很多。你只需要在內存中有一個每個guid的副本,而當你打到where子句時不需要兩個副本。

相關問題