【问题标题】:What is the best way to optimize or "tune" LINQ expressions?优化或“调整”LINQ 表达式的最佳方法是什么?
【发布时间】:2010-10-14 02:19:48
【问题描述】:

在构造 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 表达式,然后将迭代计数相加并与最大允许迭代计数进行比较。

Cameron's answer here

【问题讨论】:

    标签: linq optimization query-optimization metrics


    【解决方案1】:
    1. 获取描述所需整体性能的 SLA(或其他定义)。

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

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

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

    5. 转到 1。

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

    【讨论】:

      【解决方案2】:

      你基本上需要计算出复杂度函数。这取决于操作员,但不幸的是,文档往往不是很好。

      (对于一般原则,我同意 Richard 的回答 - 这只是 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)

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

      【讨论】:

        【解决方案3】:

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

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

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

        • 选择
        • 在哪里

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

        • 订购者
        • 除了(完全处理其他集合)

        【讨论】:

          猜你喜欢
          • 2013-10-23
          • 1970-01-01
          • 2013-09-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多