2012-10-09 212 views
1

我想在.NET Framework 4.0中利用parallel for循環。但是我注意到,我在結果集中缺少一些元素。並行For循環

我有一段代碼如下。 lhs.ListData爲空雙和rhs.ListData列表爲空雙列表。

int recordCount = lhs.ListData.Count > rhs.ListData.Count ? rhs.ListData.Count : lhs.ListData.Count; 

List<double?> listResult = new List<double?>(recordCount); 
var rangePartitioner = Partitioner.Create(0, recordCount); 

Parallel.ForEach(rangePartitioner, range => 
        { 
         for (int index = range.Item1; index < range.Item2; index++) 
         { 
          double? result = lhs.ListData[index] * rhs.ListData[index]; 
          listResult.Add(result); 
         } 
        }); 

lhs.ListData具有7964和長度rhs.ListData具有7962.長度當我執行 「*」 操作,listResult僅具有7867作爲輸出。兩個輸入列表中都有空元素。

我不知道什麼是執行過程中發生的事情。爲什麼我在結果集中看到更少的元素有什麼原因嗎?請指點...

+0

請[不要在帖子中使用簽名或標語(http://stackoverflow.com/faq#signatures)。 – meagar

回答

2

正確的方式做,這是使用LINQ的IEnumerable.AsParallel()推廣。它爲你完成所有的分區,而PLINQ中的所有內容都是線程安全的。還有另一個名爲Zip的LINQ擴展,它將兩個集合合併成一個,這取決於您提供的功能。然而,這並不是你所需要的,因爲它只能達到兩個列表中較短的列表的長度,而不是更長。這可能很容易,但首先將兩個列表中較短的一個擴展爲較長的列表,方法是在列表末尾填充null

IEnumerable<double?> lhs, rhs; // Assume these are filled with your numbers. 
double?[] result = System.Linq.Enumerable.Zip(lhs, rhs, (a, b) => a * b).AsParallel().ToArray(); 

這裏的MSDN頁面上Zip

http://msdn.microsoft.com/en-us/library/dd267698%28VS.100%29.aspx

+0

感謝您的回覆。對我來說它工作得很好。我總是需要輸出較短的列表。我將如何更改上面的邏輯部分,我需要檢查b == 0? –

+0

'(a,b)=> a * b'的部分只是一個常規lambda,你可以用任何'Func ',包括你的課堂中的一種方法。 –

0

這可能是因爲在List<T>(例如Add)的操作不是線程安全的 - 結果可能會不同。作爲解決方法,您可以使用鎖定,但這會極大地降低性能。

看起來你只是想在結果列表中的每個項目是對應的索引在兩個輸入列表中的項目的產品怎麼樣,而不是使用PLINQ:

var listResult = lhs.AsParallel() 
        .Zip(rhs.AsParallel(), (a,b) => a*b) 
        .ToList(); 

不知道爲什麼你在這裏選擇了並行性,如果這是必要的,我會進行基準測試 - 這是否真的是應用程序中的瓶頸?

+0

這個假設由MSDN上的'List '頁面確認。它聲明'List '對於同時閱讀是線程安全的,但不適用於書寫。鎖定列表也是它提供的建議。 –

0

您正在使用List<double?>存儲結果,但Add方法不是線程安全的。 您可以用明確的指標來存儲結果(而不是調用Add):

listResult[index] = result;