2013-12-09 74 views
1

我做了一些實驗性的Plinq查詢,並且我不確定結果是否會被破壞。Plinq使用StringBuilder的聚合擴展

下面是3種不同的方法,它提供了相同的結果:

// unitTask is typeof Task<List<SomeEntity>> 

     //sequential version PLINQ 
     Console.WriteLine(unitTask.Result.Take(10) 
      .Aggregate(new StringBuilder(), 
      (text, current) => text.AppendFormat("@{0}sa{1}", 
       current.FullName.Substring(0, 3), 
       current.FullName.Substring(4))) 
      .ToString()); 

     //parallel version PLINQ 
     Console.WriteLine(unitTask.Result.Take(10).AsParallel() 
      .Aggregate(new StringBuilder(), 
      (text, current) => text.AppendFormat("@{0}sa{1}", 
       current.FullName.Substring(0, 3), 
       current.FullName.Substring(4))) 
      .ToString()); 

     //parallel version foreach with Partitioner 
     var output = new StringBuilder(); 
     Parallel.ForEach(Partitioner.Create(unitTask.Result.Take(10)), r => 
     { 
      //Console.WriteLine(Thread.CurrentThread.ManagedThreadId); 
      output.AppendFormat("@{0}sa{1}", r.FullName.Substring(0, 3), 
       r.FullName.Substring(4)); 
     }); 

     Console.WriteLine(output.ToString()); 

我的問題是:

我可以在PLINQ使用StringBuilder? 由於我知道附加方法不是線程安全的。

或者它在這種情況下以順序模式運行?

Parallel.Foreach在不同的線程中運行查詢,但結果與順序Plinq相同。

它是偶然的,還是很聰明,並使用一些同步?

回答

1
  1. 此版本不使用PLINQ,它使用標準LINQ,所以它是安全的。

  2. 該版本使用了不可安全並行化的Aggregate()的重載,所以它也會在單個線程上執行。這意味着它是安全的,但它也不會比順序版本更快。

    要真正利用PLINQ,您需要使用實際可以並行執行的another overload of Aggregate()。在你的情況下,這意味着要爲每個線程分別設置StringBuilder,然後將所有StringBuilder合併成一個。喜歡的東西:

    input.AsParallel().Aggregate(
        () => new StringBuilder(), 
        (text, current) => text.AppendFormat("@{0}", current.FullName), 
        (text1, text2) => text1.Append(text2), 
        text => text.ToString()) 
    

    這裏假設你不關心最後一個字符串元素的順序。如果你這樣做,這段代碼將無法正常工作。

  3. 此代碼修改多個線程中相同的StringBuilder對象。 StringBuilder不是線程安全的,所以這段代碼是不安全的。

+0

經過進一步的調查和測量,我得到了類似的結果(單線程和慢於純序列linq)。感謝您的確認,以及替代方案。 – speti43

0

這是偶然的,可能是因爲代碼沒有做太多並且可能在單個線程上運行。您的所有電話都會涉及unitTask.Result,這些電話會阻止,直到unitTask完成。所有片段的實際工作的只有10順序產生的實體,所以沒有足夠的數據來證明並行執行

三段做不同的事情:

  1. 的第一個片段只是順序處理的10段的清單。
  2. PLINQ版本包含10個實體的列表,但並不做任何事情。即使這樣做,致電Aggregate也會收集所有員工的結果,並按順序處理它們以創建最終結果。
  3. 第三個代碼段可能會顯示並行行爲,因爲它並行執行一個操作塊。再次,結果數量太少,只有一個線程用於
+0

第三個片段爲我使用4個線程。簡單的字符串對象在這種情況下是更好的選擇 – speti43

+0

我的意思是你比較不同的事情。這不是線程安全問題。即使你連接了字符串,你也會得到不一致的結果,因爲每個線程在每次迭代時都會看到不同的輸入字符串。無論如何,你想要解決什麼問題?如果你想記錄進度,Console.WriteLine綽綽有餘 –

+0

正如我寫的這是一個實驗性的任務,瞭解這些組件如何工作。我不想解決任何問題。只比較順序執行和並行執行。所以你說,並行串聯字符串不是一個好主意。 – speti43