使用 Parallel.ForEach<T> 添加到新列表<T>

Using Parallel.ForEach<T> to add to a new List<T>

使用并行化(例如 Parallel.ForEach)的最佳方式是什么,这样我就可以快速迭代集合并将项目添加到新列表而不违反线程安全,但可以利用多个服务器内核的性能增益和有足够的 RAM?

public List<Leg> FetchLegs(Trip trip)
{
    var result = new List<Leg>();

    try
    {
        // get days
        var days = FetchDays(trip);

        // add each day's legs to result
        Parallel.ForEach<Day>(days, day =>
        {
            var legs = FetchLegs(day);
            result.AddRange(legs);
        });

        // sort legs by scheduledOut
        result.Sort((x, y) => x.scheduledOut.Value.CompareTo(y.scheduledOut.Value));

    }
    catch (Exception ex)
    {
        SiAuto.Main.LogException(ex);
        System.Diagnostics.Debugger.Break();
    }

    return result;
}

最简单的解决方案是使用 PLINQ 及其扩展方法,如 ToListToDictionary。示例:

var result = days.AsParallel().SelectMany(d => FetchLegs(d))
                 .OrderBy(l => l.scheduledOut.Value).ToList();

除了使用像 ConcurrentQueue 这样的线程安全结构来确保并行循环中的线程安全,或者您可以考虑使用自定义线程安全列表,请查看我的以下内容 post - Thread safe List。事实上,您可以考虑使用 ReaderWriterSlim 锁来代替普通的 lock。 另一个重点是,您可以考虑使用 ParallelOptions MaxDegreeOfParallelism,检查 here 的值是否等于 Environment.ProcessorCount,这样 Parallel.ForEach 分区程序就可以正常工作,而不是开始时为集合中的每个数据点创建一个任务,它会根据系统中的逻辑核心数来执行,从而有效减少线程上下文切换,使应用程序更加高效