LINQ 查询是不是有很多开销?

Posted

技术标签:

【中文标题】LINQ 查询是不是有很多开销?【英文标题】:Do LINQ queries have a lot of overhead?LINQ 查询是否有很多开销? 【发布时间】:2010-11-14 04:29:34 【问题描述】:

IEnumerable<T> 上的简单 LINQ 查询是轻量级还是重量级?它们与手动编写 forforeach 循环相比如何?是否有关于何时更喜欢 LINQ 和手动搜索的一般准则?

例如:

var lowNums =
    from n in numbers
    where n < 5
    select n;

相比:

List<int> lowNums = new List<int>();

foreach (int n in numbers)

    if (n < 5)
    
        lowNums.Add(n);
    

我正在和一位同事谈论 LINQ,他对使用它表示了一些犹豫。他猜想,为了支持 LINQ 可以做的一切,“幕后”可能会发生很多事情。

上述示例之间是否存在显着的性能差异?有没有关于集合上 LINQ 性能的好资源?简单的 Google 搜索 linq performance 会发现一些看似过时的文章。

【问题讨论】:

请记住,通过惰性评估您可能会获得性能提升,这取决于您在做什么。 可能重复:***.com/questions/1182922/… 感谢您提出这个问题,每次我将他的 LINQ 表达式重写为非 LINQ 逻辑等效项时,一位同事往往会挑起眉毛。 :P @Danny 考虑可维护性和性能之间的平衡很重要。 【参考方案1】:

调用委托会产生开销,但通常相当低。

然后是所有涉及的迭代器的开销 - 通常查询中每个额外的子句一个迭代器。再说一次,不是很大,但也不是没有。

您有实际的应用吗?如果是这样,可以在 LINQ 中完成的位性能有多重要?以我的经验,这些位通常不是瓶颈,所以如果 LINQ 稍微降低了性能,那真的没关系。不过,LINQ 可以极大地提高解决方案的可读性。

请注意,您的示例中的性能完全不同,因为两段代码做的事情非常不同。您的 LINQ 示例将在眨眼间执行,因为它实际上并没有运行查询 - 它只是设置它。如果您在末尾调用ToList() 然后,它基本上等同于您的第二个示例。在进行性能比较时要记住这一点非常重要!

要记住的另一件事 - 您不必使用查询表达式语法。如果您是 just 过滤(或 just 投影),我通常发现使用普通点符号​​调用扩展方法更有意义:

var lowNums = numbers.Where(n => n < 5);

【讨论】:

我最近在工作中构建了一个基于 LINQ to SQL 的整个应用程序......老派 sql 家伙攻击了所有进入数据库的 sql,说 linq 垃圾很慢。 ORM 很烂。所有常见的论点。当他爆发分析器时,他发现实际上是他所有的存储过程都很慢……而且 LINQ 表现得很好!我笑了。 所提供的示例代表了我将要做的事情:遍历一个简单的数组以找到一个或多个符合指定条件的项目,例如将属性设置为特定值。 @emddudley:但是之后你想对结果做什么呢? LINQ 使您可以轻松地仅在需要时使用它们,而无需创建整个列表……但这在您的情况下可能会或可能不会更有效。有多少项目?你知道你实际上有任何性能问题吗? 这个问题主要是假设性的。在我的应用程序中,我基本上想从大约 10 到 20 个对象中找到一个对象,因此性能肯定不是问题。我只是想要一种简单的方法来获取对集合中符合我的搜索条件的对象的引用。【参考方案2】:

关于 LINQ-to-objects 的唯一真正的性能开销是自己创建的几个额外的对象来帮助枚举和函数调用。简而言之,除非你以非设计的方式使用它,否则它不会影响你的表现,除非你正在做非常高性能的东西。

在这种情况下,我会先以 LINQ 的方式实现它,然后让您的性能测试告诉您在哪些特定的地方您可能需要考虑以不同的方式执行它。对于相当多的代码,易于维护胜过纯粹的性能。

【讨论】:

【参考方案3】:

这是我对 LINQ 的一般规则

当解决方案更具表现力时使用 LINQ。仅当分析器证明 LINQ 查询是问题的根源时,才切换到表达较少但速度更快的解决方案。

【讨论】:

很好的建议。如果有问题的代码从性能的角度来看不会出血,我更喜欢更具表现力的路线。事后进行的性能调整将隔离任何需要重新访问以进行重构的区域。我还没有遇到 LINQ 是问题的场景,而不是周围的实现和/或不合理的假设。【参考方案4】:

LINQ in Action 的作者对for, foreach, List&lt;T&gt;.FindAll 进行了一些基准测试,而 LINQ 查询都做了同样的事情。根据查询的构造方式,LINQ 只慢了大约 10%。正如他们所说,

LINQ 不是免费提供的。

LINQ 是一个复杂的主题,但根据您对它的用途,它不必增加很多开销。通常,LINQ 已构建为尽可能依赖延迟执行,以节省内存和 CPU,直到您真正需要它为止。

但是,您必须了解不同查询运算符的工作方式,因为更改查询流程可能会极大地改变查询的执行方式。您描述的简单查询通常不是问题,但是像Reverse() 这样的运算符和转换运算符可能会引发一些麻烦,因为它们需要立即迭代结果集。通常有多种方法可以编写相同的查询,并且取决于您如何构建它,您可能会看到最小的性能损失,或者您可以让它慢一倍作为等效循环。

不过,在我的大部分日常编码中,它提供的便利性和简洁性远远超过了任何性能考虑因素。永远不要预优化!

【讨论】:

从这个答案中,得出 LINQ 永远不会比非 LINQ 等价物快的结论是否准确? 我看到的另一个问题是,依赖 LINQ 通常会在开发人员团队和 DBA 团队之间产生分歧,他们更喜欢使用 T-SQL。如果您必须支持不支持使用 LINQ 的语言,您也可能会限制自己。 LINQ 没有问题,但一切都是有代价的。 @Danny:恕我直言,不是,只是因为可以以一种当您尝试使用循环手动编写相同查询时不会做的方式优化一个琐碎的 Linq 查询(如 list1.Except(list2))。 @TimSchmelter 谢谢你的例子!【参考方案5】:

让自己相信 LINQ 的一个好方法是使用 LINQPad。它允许您为 LINQ 和非 LINQ 实现输出 IL(如果您使用的是 LINQ2SQL,还可以输出 SQL)。

通常,当我对“幕后”到底发生了什么有疑问时(正如您的同事想知道的那样),我会去 IL 亲自了解情况。我所看到的绝大多数情况是 LINQ 的实现非常出色。

【讨论】:

【参考方案6】:

根据LINQ In Action (pg.198):

“LINQ 不是免费的。LINQ 查询导致额外的工作,对象 创作,对垃圾的压力 集电极。的额外费用 使用 LINQ 可能会有很大差异,具体取决于 查询。它可以低至 5 百分比,但有时可能在 500%。”

【讨论】:

我的个人经验表明,用于非常小的数据集的 LINQ 通常表现不佳。这确实显示了 LINQ 在经常重复的循环中的位置。我将 LINQ 更改为 for 循环并缩短了进程的时间。这当然是一个边缘案例。

以上是关于LINQ 查询是不是有很多开销?的主要内容,如果未能解决你的问题,请参考以下文章

求科普,SQL查询开销是啥意思?100%好,还是50%好?

低基数列索引 VS 表开销

使用可变长度数组是不是有任何开销?

在 Python 中嵌套函数时是不是有开销?

在内存中缓存 Spark 数据帧是不是有额外的开销?

mysql UPDATE 语句 - 相同值的开销?