2012-05-22 28 views
1

我試圖想出一種方法來加速以最快的方式將列表中包含的大量對象組合起來。希望利用PLINQ我嘗試過,但這不是一個線程安全的解決方案。我已經在VS2010和VS11Beta中測試過4.0和4.5。這是我的示例應用程序。如果你在1-500之間改變BlowUp(),它通常會起作用。 500後輪子來自賽道。它會在多個地方失敗。有沒有人知道解決這個問題的最快方法? (多維數組+ PLINQ?)PLINQ對於.NET 4.0和4.5中的所有破解

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace PLinqBlowsUp 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     BlowUp(5000); 
    } 

    private static void BlowUp(int blowupNum) 
    { 
     try 
     { 
      var theExistingMasterListOfAllRowsOfData = new List<List<KeyValuePair<string, dynamic>>>(); 

      //Add some test data 
      Enumerable.Range(0, blowupNum).AsParallel().ForAll(row => theExistingMasterListOfAllRowsOfData.Add(AddRowToMasterList(row))); 


      var aNewRowOfData = new List<KeyValuePair<string, dynamic>>(); 
      //Add some test data 
      var column = new KeyValuePair<string, dynamic>("Title", "MyTitle"); 
      aNewRowOfData.Add(column); 

      var anotherNewRowOfData = new List<KeyValuePair<string, dynamic>>(); 
      //Add some test data 
      var columnA = new KeyValuePair<string, dynamic>("Date", DateTime.Now); 
      var columnB = new KeyValuePair<string, dynamic>("ImportantColumn", "ImportantData"); 
      var columnC = new KeyValuePair<string, dynamic>("VeryImportantColumn", "VeryImportantData"); 
      anotherNewRowOfData.Add(columnA); 
      anotherNewRowOfData.Add(columnB); 
      anotherNewRowOfData.Add(columnC); 

      //Now the Problem 
      aNewRowOfData.AsParallel().ForAll(anrod => theExistingMasterListOfAllRowsOfData.ForEach(temloarod => temloarod.Add(anrod))); 
      anotherNewRowOfData.AsParallel().ForAll(anrod => theExistingMasterListOfAllRowsOfData.ForEach(temloarod => temloarod.Add(anrod))); 

      //Test for number 
      foreach (var masterRow in theExistingMasterListOfAllRowsOfData) 
      { 
       if (masterRow.Count != 7) 
        throw new Exception("BLOW UP!!!"); 
      } 
     } 
     catch (AggregateException ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
    } 

    private static List<KeyValuePair<string, dynamic>> AddRowToMasterList(int row) 
    { 
     var columnA = new KeyValuePair<string, dynamic>("FirstName", "John" + row.ToString()); 
     var columnB = new KeyValuePair<string, dynamic>("LastName", "Smith" + row.ToString()); 
     var columnC = new KeyValuePair<string, dynamic>("Ssn", 123456789 + (row*10)); 

     var list = new List<KeyValuePair<string, dynamic>>(); 
     list.Add(columnA); 
     list.Add(columnB); 
     list.Add(columnC); 
     return list; 
    } 
} 
} 
+0

採取下面的建議......目前正嘗試使用KVP的多維陣列的ForAll來爲此類型進程提供多個內核的速度。 – YurikoEX

+1

誰喜歡這樣一個問題?它指出「PLinq的ForAll不起作用」,這很簡單,不正確,只顯示來自提問者的誤解(這是合法的;沒有人知道所有事情,但問題在目前的形式中是不好的)。 ForAll被破解的機會有多少,到現在爲止還沒有人意識到這一點? – sloth

回答

3

我看到兩個問題。

  • 您從多個線程調用的theExistingMasterListOfAllRowsOfData實例Add沒有任何企圖訪問與其同步。
  • 您致電Add對個人List<KeyValuePair<string, dynamic>>項目從多個線程沒有任何嘗試同步它們。

你可以使用lock保護Add方法或使用ConcurrentBag代替。但是,這些選項都不是那麼好。這裏的問題是這種操作不能很好地並行化,因爲所有的線程最終都會爭奪同一個鎖。我高度懷疑,即使低鎖ConcurrentBag最終會比剛剛在PLINQ上踢出來的速度慢,並在主線程上完成所有任務。

2

PLinq不能替代編寫線程安全代碼。您訪問theExistingMasterListOfAllRowsOfData不是線程安全的,因爲它正在被線程池中的所有線程訪問。你可以嘗試它周圍的鎖定,這解決了這個問題對我來說:

Enumerable.Range(0, blowupNum).AsParallel().ForAll(row => { 
    lock (theExistingMasterListOfAllRowsOfData) {     
     theExistingMasterListOfAllRowsOfData.Add(AddRowToMasterList(row)); 
    } 
}); 

然而,鎖定可能不是你以後,因爲這將引入瓶頸。

+0

我想過鎖定,但是首先要做的就是完成ForAll()。 – YurikoEX

+1

當然,但重點是PLink只是另一種分配和使用多線程的方式。您必須意識到編寫多線程代碼的所有缺陷和挑戰,無論您是創建自己的線程,還是從線程池手動拉出線程,或者使用PLink。 –

4

這與PLinq無關 - 將項目添加到List<T>根本不是線程安全的。可能會降低性能的可行解決方案是引入鎖定。你通常想做的事情是投射到一個新的集合作爲你的PLinq語句的結果 - 引入你所做的副作用並不是Linq /函數式編程的精神,你可能會遇到麻煩(如你所做的那樣)。

+0

ForAll似乎還有更多。如果我不想首先影響我的列表,我不會成爲ForEach/ForAll'ing他們。只是讓ForAll對列表來說顯得毫無意義(因爲我必須想出一個通過鎖定來阻止它的方法)。但是做一個.ForEach來影響我的收藏完全是Linq的精神。那麼爲什麼不是.ForAll? – YurikoEX

相關問題