【发布时间】:2012-02-04 04:58:12
【问题描述】:
一段时间以来,我一直在围绕没有副作用的方法构建我的代码,以便使用并行 linq 来加快速度。在此过程中,我不止一次偶然发现惰性评估使事情变得更糟而不是更好,我想知道是否有任何工具可以帮助优化并行 linq 查询。
我之所以这么问是因为我最近通过修改一些方法并在某些关键位置添加AsParallel 来重构一些令人尴尬的并行代码。运行时间从 2 分钟下降到 45 秒,但从性能监视器中可以清楚地看出,有些地方 CPU 上的所有内核都没有得到充分利用。在几次错误启动后,我使用ToArray 强制执行一些查询,运行时间进一步下降到 16 秒。减少代码的运行时间感觉很好,但也有点令人不安,因为不清楚代码查询的哪个位置需要使用ToArray 强制执行。等到最后一分钟才执行查询并不是最佳策略,但根本不清楚代码中的哪些点需要强制执行某些子查询才能利用所有 CPU 内核。
因为我不知道如何正确地使用 ToArray 或其他强制执行 linq 计算的方法以获得最大的 CPU 利用率。那么是否有任何通用指南和工具来优化并行 linq 查询?
这是一个伪代码示例:
var firstQuery = someDictionary.SelectMany(FirstTransformation);
var secondQuery = firstQuery.Select(SecondTransformation);
var thirdQuery = secondQuery.Select(ThirdTransformation).Where(SomeConditionCheck);
var finalQuery = thirdQuery.Select(FinalTransformation).Where(x => x != null);
FirstTransformation、SecondTransformation、ThirdTransformation 都受 CPU 限制,就复杂性而言,它们是一些 3x3 矩阵乘法和一些 if 分支。 SomeConditionCheck 几乎是 null 支票。 FinalTransformation 是代码中 CPU 最密集的部分,因为它将执行一大堆线平面相交,并检查这些相交的多边形包含情况,然后提取最接近线上某个点的相交。
我不知道为什么我放置AsParallel 的地方会减少代码的运行时间。我现在在运行时间方面达到了局部最小值,但我不知道为什么。我偶然发现它只是运气不好。如果您想知道放置AsParallel 的位置是第一行和最后一行。将AsParallel 放在其他任何地方只会增加运行时间,有时最多会增加 20 秒。第一行还有一个隐藏的ToArray。
【问题讨论】:
-
AsParallel的情况与非并行查询相同。在评估查询之前什么都不会发生。您必须迭代或以其他方式执行查询。 -
@AnthonyPegram:我明白这一点。我不是无缘无故地创建查询。它们将在程序中的某个点使用,但该点可能不一定是强制计算的最佳位置。事实上,它甚至可能会减慢速度。而如果一些子查询是强制执行的,那么整个计算速度会大大加快。
-
请提供一些示例代码,以便我们可以想象一般解释背后的一些东西,并用具体的代码建议来回答。
-
这听起来你会不小心对一个序列进行两次迭代。否则,使用 .ToArray() 并没有真正的好处
-
在通过反复试验开始优化之前使用分析器。
标签: c# linq c#-4.0 parallel-processing plinq