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

本文关键字:lt gt 列表 新列表 Parallel 使用 添加 ForEach | 更新日期: 2023-09-27 18:01:00

使用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;
}

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

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

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

将注释转移到答案,并提供更多建议,除了在Parallel循环中使用线程安全结构(如ConcurrentQueue(来实现线程安全之外,或者您可以考虑自定义线程安全列表,请查看我下面的帖子-线程安全列表。事实上,您可以考虑用ReaderWriterSlim锁来代替普通的lock。另一个重要的点是,你可以考虑使用ParallelOptions MaxDegreeOfParallelism,在这里检查值等于Environment.ProcessorCount,这样Parallel.ForEach partitioner就可以很好地工作,通过一开始不为集合中的每个数据点创建任务,它将根据系统中逻辑核心的数量来执行,从而有效地减少了线程上下文切换,并使应用程序更加高效。