3

在构造 LINQ 表达式(对我来说,是 linq to objects)时,有很多方法可以完成某事,有些方法比其他方法好得多、效率高。

  • 有没有“调整”或优化这些表达式的好方法?
  • 人们使用哪些基本指标,您如何收集它们?
  • 有没有办法获得“总迭代次数”计数或其他一些指标,您可以“知道”越低意味着越好?

编辑

感谢理查德/乔恩的回答。

看起来我真正想要的是一种为 LINQ 表达式获取简单操作计数“OCount”的方法,尽管我不确定 LINQ 中是否存在允许它的钩子。假设我有一个特定机器硬件(SLA)的目标性能水平。理想情况下,我会添加一个单元测试来确认通过该查询移动的典型数据将在分配的时间内(来自 SLA)处理。问题是这将在构建服务器/开发人员机器/等上运行。这可能与 SLA 的机器硬件几乎没有相似之处。所以我的想法是,我将为表达式确定一个可接受的最大“OCount”,知道如果 OCount 小于 X,它肯定会在目标“典型”硬件上在 SLA 下提供可接受的性能。如果 OCount 超过此阈值,构建/单元测试会产生警告。理想情况下,我想要这样的东西(伪代码):

var results = [big linq expression run against test dataset];
Assert.IsLess(MAXALLOWABLE_OCOUNT, results.OCount)

其中 results.OCount 只会给我生成结果集所需的总迭代次数 (n)。

为什么我会喜欢这个??

好吧,即使是大小适中的 LINQ 表达式,由于增加了整体操作数,微小的更改/添加也会对性能产生巨大影响。应用程序代码仍然会通过所有单元测试,因为它仍然会产生正确的结果,但在部署时运行缓慢。

另一个原因是简单的学习。如果你做某事并且 OCount 上升或下降一个数量级,那么你就会学到一些东西。

编辑#2 我也会提出一个潜在的答案。这不是我的,它来自Cameron MacFarland,来自我问的另一个问题,它产生了这个问题。事实证明,我认为这个问题的答案可以在单元测试环境中工作,就像我在第一次编辑这个问题时描述的那样。

它的本质是在单元测试夹具中创建测试数据集,您按照此答案中概述的方式将其输入 LINQ 表达式,然后将迭代计数相加并与最大允许迭代计数进行比较。

在这里查看卡梅伦的答案

4

3 回答 3

6

您基本上需要计算出复杂度函数。这取决于操作员,但不幸的是,这往往没有很好的记录。

(对于一般原则,我同意理查德的回答——这只是 LINQ to Objects 的东西。)

如果您有感兴趣的特定运营商,那么值得询问他们,但在我的脑海中:

  • 选择 = O(n)
  • 其中 = O(n)
  • Join = O(inner + outer + matches) (即它不比 便宜inner + outer,但可能与结果一样糟糕inner * outer
  • GroupJoin = 与 Join 相同,但由外部缓冲而不是流式传输
  • OrderBy = O(n log n)
  • SelectMany = O(n + 结果)
  • Count = O(1) 或 O(n) 取决于它是否实现 IList
  • 计数(谓词)= O(n)
  • 最大值/最小值 = O(n)
  • All/Any = O(n)(可能提前退出)
  • 不同 = O(n)
  • 跳过/采取 = O(n)
  • SkipWhile/TakeWhile = O(n)

确切的特征取决于操作员是缓冲还是流。

于 2009-03-18T14:43:56.087 回答
3
  1. 获取描述所需整体性能的 SLA(或其他定义)。

  2. 测量应用程序性能,以及它低于要求的程度(如果在要求范围内,则停止并做一些有用的事情)。

  3. 使用分析器获取详细的性能细分,确定系统中最可以改进的部分(对热门代码进行小幅改进可能比对很少被调用的代码进行大改进要好)。

  4. 进行更改,重新运行单元/功能测试(没有必要快速做错事)。

  5. 转到 1。

如果在 #3 中您发现 LINQ 表达式是一个性能问题,那么请开始考虑需要对这个问题的答案。答案将完全取决于您使用的 LINQ 提供程序以及在您的情况下使用它的详细信息。没有普遍的答案。

于 2009-03-18T14:37:11.297 回答
0

添加到正在添加到理查德的 Jon

要考虑的另一个问题是您是否正在处理 LINQ 查询的所有结果。在某些情况下,尤其是 UI,您最终只处理从 LINQ 查询返回的结果的子集。在这些情况下,了解哪些 LINQ 查询支持惰性求值很重要。这是在不处理整个集合的情况下返回结果子集的能力。

例如,在以下 LINQ 操作上调用 MoveNext() 将一次处理一个结果

  • 选择
  • 在哪里

但是以下必须在返回单个项目之前处理集合中的每个元素。

  • 排序依据
  • 除了(完全处理其他集合)
于 2009-03-18T15:14:26.013 回答