2013-06-03 46 views
0

我正嘗試使用多線程來更快地處理結果列表。我嘗試使用並行,但每當運行過程方法時,我都沒有收到正確的結果。如何多線程處理方法

private IEnumerable<BulkProcessorResult> GetProccessResults(List<Foo> Foos) 
{ 
    var listOfFooLists = CreateListOfFooLists(Foos); 

    var bulkProcessorResults = new List<BulkProcessorResult>(); 
    Parallel.ForEach(listOfFooLists, FooList => 
    { 
     foreach (var Foo in FooList) 
     { 
      var processClaimResult = _processor.Process(Foo); 
      var bulkProcessorResult = new BulkProcessorResult() 
      { 
       ClaimStatusId = (int) processClaimResult.ClaimStatusEnum, 
       Property1 = Foo.Property1 
      }; 
      bulkProcessorResults.Add(bulkProcessorResult); 
     } 
    }); 

    return bulkProcessorResults; 
} 

如果我使用正常forEach我得到正確的輸出。如果我使用上面的代碼,當狀態爲1,狀態爲3時,我得到全部2的狀態。'

我對線程真的很陌生,所以任何幫助都會很棒。

+0

什麼是languge?您應該將其添加到標籤。 –

+2

你可能想看看例如作爲中間商店的['ConcurrentQueue '](http://msdn.microsoft.com/zh-cn/library/dd267265.aspx)。 'List '不安全(例如通過調用'Add')來處理多個線程。任何事情都可能發生(也可能會發生)。 –

+3

我看到的第一個問題是,您有多個併發線程將項目添加到'buldProcessResults'。這會導致問題,因爲'List.Add'不能用於多個併發更新。你需要用鎖來保護它,或者使用某種類型的併發數據結構。 –

回答

3

最明顯的問題是,你正在使用多線程工作(好吧,這在一定程度上通過調用Parallel.ForEach隱藏,但你應該知道,它利用多線程/任務的並行實現),但你」重新使用List<T>,這是不是線程安全的集合類:

一個List<T>可以支持多個讀者同時,只要收集不被修改。枚舉枚舉本質上不是一個線程安全的過程。在枚舉與一個或多個寫入訪問競爭的罕見情況下,確保線程安全的唯一方法是在整個枚舉期間鎖定集合。要允許被多個線程進行讀取和寫入訪問的集合,則必須實現自己的同步

而不是實現自己的同步,不過,同時不改變很多其他在你的代碼,我會切換到使用一個ConcurrentQueue<T>

private IEnumerable<BulkProcessorResult> GetProccessResults(List<Foo> Foos) 
{ 
    var listOfFooLists = CreateListOfFooLists(Foos); 

    var bulkProcessorResults = new ConcurrentQueue<BulkProcessorResult>(); 
    Parallel.ForEach(listOfFooLists, FooList => 
    { 
     foreach (var Foo in FooList) 
     { 
      var processClaimResult = _processor.Process(Foo); 
      var bulkProcessorResult = new BulkProcessorResult() 
      { 
       ClaimStatusId = (int) processClaimResult.ClaimStatusEnum, 
       Property1 = Foo.Property1 
      }; 
      bulkProcessorResults.Enqueue(bulkProcessorResult); 
     } 
    }); 

    return bulkProcessorResults; 
} 
+1

你也可以使用'ConcurrentBag '。 –

+0

@JimMischel你有什麼經驗說明'ConcurrentBag'在這種情況下會更有效嗎?據我所知,當每個線程都是生產者和消費者時,'ConcurrentBag'效果最好,在這裏情況並非如此。 – svick

+0

@svick:我沒有關於'ConcurrentBag'相對於'ConcurrentQueue'的速度的信息。我只是提到另一種選擇。 –

1

如何將整個事物視爲並行Linq查詢?

private IEnumerable<BulkProcessorResult> GetProccessResults(List<Foo> Foos) 
{ 
    var listOfFooLists = CreateListOfFooLists(Foos); 
    return listOfFooLists.AsParallel() 
         .SelectMany(FooList => FooList) 
         .Select(Foo => 
          new BulProcessorResult { 
           ClaimStatusId = (int)_processor.Process(Foo), 
           Property1 = Foo.Property1 
          }).ToList(); 
}