IEnumerable<T>
轻量级或重量级的简单LINQ查询?他们如何与手写for
或foreach
循环相比较?何时更喜欢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性能?一个简单的谷歌搜索linq performance发现了一些看似过时的文章。
答案 0 :(得分:18)
LINQ in Action的作者使用for, foreach, List<T>.FindAll
进行了一些基准测试,并且LINQ查询都做了同样的事情。根据查询的构造方式, LINQ仅慢了约10%。正如他们所说,
LINQ不是免费的。
LINQ是一个复杂的主题,但根据你使用它做什么,它不需要增加很多开销。通常,LINQ的构建依赖于延迟执行,以节省内存和CPU,直到您真正需要它为止。
但是,您必须了解不同的查询运算符是如何工作的,因为更改查询流可能会大大改变它的执行方式。您描述的简单查询通常不是问题,但像Reverse()
和转换运算符这样的运算符可能会抛出一些问题,因为它们需要立即迭代结果集。通常有多种方法可以编写相同的查询,而取决于您构建它的方式,您可以查看最小的性能损失,或者可以使其速度慢两倍作为等价的循环。
它提供的便利性和简洁性远远超过我日常编码的大部分性能考虑因素。永远不要预先优化!
答案 1 :(得分:15)
这是我对LINQ的一般规则
当解决方案更具表现力时使用LINQ。当探查器证明LINQ查询是问题的根源时,只切换到表达力较低但速度较快的解决方案。
答案 2 :(得分:10)
调用委托的开销很大,但通常都很低。
然后是所涉及的所有迭代器的开销 - 通常在查询中每个extra子句有一个迭代器。再次,不是一个巨大的数额,但也不是什么。
您是否考虑过实际应用?如果是这样,那么在LINQ中可以完成的性能有多重要?根据我的经验,这些位通常不瓶颈,所以如果LINQ稍微降低性能,那真的无关紧要。 LINQ 可以对您的解决方案的可读性做出很大贡献。
请注意,示例中的性能完全不同,因为这两段代码的功能完全不同。您的LINQ示例将在眨眼间执行,因为它实际上并不是正在运行查询 - 它只是设置它。如果你在结束时调用ToList()
,那么它基本上等同于你的第二个例子。在进行性能比较时,记住这类事情非常重要!
要记住的另一件事 - 您不必使用查询表达式语法。如果您只是过滤(或只是投影),我通常会发现使用普通的点符号调用扩展方法更有意义:
var lowNums = numbers.Where(n => n < 5);
答案 3 :(得分:3)
关于LINQ-to-objects自己做的唯一真正的性能开销是为了帮助枚举和函数调用而创建的少数额外对象。简而言之,除非你以一种不适合的方式使用它,否则它不会损害你的表现,除非你做的是非常高性能的东西。
在这种情况下,我首先使用LINQ方式实现它,并让您的性能测试告诉您在不同的地方可能需要考虑哪些特定的位置。对于相当多的代码,易于维护胜过纯粹的性能。
答案 4 :(得分:3)
根据LINQ In Action(第198页):
“LINQ不是免费的.LINQ 查询导致额外的工作,对象 创造和对垃圾的压力 集电极。额外费用 使用LINQ可能会有很大差异,具体取决于 查询。它可以低至5 百分比,但有时可以在附近 500%。“
答案 5 :(得分:2)
让自己说服LINQ的一个好方法是使用LINQPad。它允许您为LINQ和非LINQ实现输出IL(如果您使用的是LINQ2SQL,则输出SQL)。
有时候,当我对“幕后”发生的事情提出疑问时(正如你的同事所想的那样),我会去IL找我自己。我所看到的绝大部分时间都是LINQ的无足轻重。