1

我必須刪除對象從Parallel.ForEach。我應該使用ConcurrentBag還是隻刪除它?沒有對象是否線程安全?這些列表在Parallel.For中是否安全線程?

resultsList<>

Parallel.ForEach(entityList, options, 
() => 
{ 
    List<Customer> childrenResult = new List<Customer>(); 
    return childrenResult; 
}, 
(childrenObject, loopState, childrenResult) => 
{ 
    childrenResult.AddRange(currentChildrenManager.Prepare(childrenObject, currentAnalyticalDataHolder,() => loopState.IsStopped, out childrenAllData)); 
    return childrenResult; 
}, 
(childrenResult) => 
{ 
    lock (lockingObject) 
    { 
     if (childrenResult == null) 
      results.AddRange(new List<Customer>()); 
     else if (currentChildrenManager.RowOrFilteredRowLimitation == null) 
      results.AddRange(childrenResult); 
     else 
     { 
      int leftCount = currentChildrenManager.RowOrFilteredRowLimitation.GetRelativRowLimitation(provider.IsForGenerationTime) - results.Count(); 
      if (leftCount > 0) 
      { 
       if (childrenResult.Count() > leftCount) 
       { 
        tAllData = currentChildrenManager.OnlyFirst; 
        results.AddRange(childrenResult.Take(leftCount)); 
       } 
       else 
        results.AddRange(childrenResult); 
      } 
      else 
      { 
       tAllData = currentChildrenManager.OnlyFirst; 
      } 
     } 
    } 
}); 

回答

1

我假設你提出的代碼使用這需要在localInit值分別使用localFinallyFunc<T>Action<T>超載,看起來像這樣:

public static ParallelLoopResult ForEach<TSource, TLocal>(
    IEnumerable<TSource> source, 
    ParallelOptions parallelOptions, 
    Func<TLocal> localInit, 
    Func<TSource, ParallelLoopState, TLocal, TLocal> body, 
    Action<TLocal> localFinally 
) 

鎖定仍然是必須的,因爲最終操作必須將項目並行添加到底層列表。你可能使用ConcurrentBag<T>進行最後的連接,但我建議你基準兩種方式來看看哪個給你更高性能的結果。

也許另一種更適合你的方法是使用PLINQ。這樣,您可以並行操作多個項目,並且只能在最後使用ToList創建一個包含結果的List<T>

var result = entityList.AsParallel() 
         .Select(childObject => 
           currentChildrenManager.Prepare(
         childObject, currentAnalyticalDataHolder, out childrenAllData)) 
         .ToList(); 
// Modify the list further if needed.