为了优化 C# 应用程序的性能,我遇到了AsParallel()
LINQ。我想了解它们之间的主要区别,特别是在处理较大数据集或昂贵计算时的性能方面。
情景 1:无
AsParallel()
- 针对项目集合按顺序执行 Where 查询。
- 过滤
(i => i.Name == currentItem.Name)
每次评估一个项目。 - 只有外循环(
Parallel.ForEach()
)受益于并行性,其中 currentItem 在多个线程中处理。 - 这种方法看起来更简单,并且适用于小型数据集或轻量级 LINQ 操作。
var result = new List<Item>();
Parallel.ForEach(items, currentItem =>
{
var filteredItems = items.Where(i => i.Name == currentItem.Name);
result.AddRange(filteredItems);
});
场景 2:
AsParallel()
var result = new List<Item>();
Parallel.ForEach(items, currentItem =>
{
var filteredItems = items.AsParallel().Where(i => i.Name == currentItem.Name);
result.AddRange(filteredItems);
});
我想知道AsParallel()
在内部 LINQ 查询(部分.Where()
)上使用是否会带来过多的开销或复杂性,从而对某些工作负载产生反作用。您能否提供一些指导,说明何时适合AsParallel()
同时用于外部和内部操作,以及何时实际上可能会减慢速度?
您的两个例子都不正确。
List<T>
不是线程安全的,因此result.AddRange(filteredItems);
几乎肯定会产生不正确的结果。第一步应该是考虑您是否使用了合适的算法。您不太清楚自己想要做什么,但它看起来像分组操作?那样的话
items.GroupBy(i => i.Name)
肯定会更好。或者只是按名称对列表进行排序?这两种方法的算法复杂度都较低,因此几乎肯定比并行化更受欢迎。您很少会想要使用多级并行,因为这会增加开销并导致性能下降。因此,将
Parallel.ForEach
和组合起来AsParallel
可能不是一个好主意。我将它们视为替代方案,如果您的问题最容易用 for/foreach 循环来表达,请使用Parallel.For/Foreach
。如果问题最好用 LINQ 来表达,请使用.AsParallel
。但不要以为所有问题都能从并发中获益。并行化有一些开销,你需要考虑。在尝试任何类型的优化之前,你应该做一些测量和/或基准测试,这样你就知道你的改变是否真的带来了改进,以及代码是否慢到需要首先进行优化。
这毫无意义。它总是会拖慢进程。
并行处理的目的是利用在一次只做一件事时未充分利用的资源。例如,我的 PC 有 4 个 CPU 核心,因此如果我一次只做一件 CPU 密集型的事情,我只会使用 4 个核心中的一个。一次做 4 件事是合理的,这样可以充分利用所有可用的核心。这是我可以从我的机器中获得的最大性能。一次做 5 件事不会提高性能,因为没有第五个 CPU 核心可供我的程序使用。4 个可用核心必须定期切换任务,以使所有 5 个任务都能取得公平进展。因此,我的程序不仅没有变得更快,现在还必须支付切换任务的额外管理成本。我毫无理由地给我的程序增加了寄生阻力。我不应该那样做。
将并行操作嵌套在另一个操作中会使实现给定工作负载的最佳并行度变得更加困难。最好将外循环并行化,并保持内循环连续。