Parallel.For 中的那些列表是安全线程吗?

Are those Lists safe thread in Parallel.For?

我必须从 Parallel.ForEach 中删除 lock 对象。我应该使用 ConcurrentBag 还是直接删除它?没有 lock 对象是线程安全的吗?

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;
            }
        }
    }
});

我假设您提供的代码使用了重载,它接受一个 localInit 值并分别使用 localFinally Func<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.