关于.NET:LINQ查询有很多开销吗?

Do LINQ queries have a lot of overhead?

IEnumerable的简单linq查询是轻量级还是重量级?与手工编写forforeach循环相比,它们有什么不同?有没有一个一般的指导方针,什么时候更喜欢LINQ而不是手动搜索?

例如:

1
2
3
4
var lowNums =
    from n in numbers
    where n < 5
    select n;

相比:

1
2
3
4
5
6
7
8
9
List<int> lowNums = new List<int>();

foreach (int n in numbers)
{
    if (n < 5)
    {
        lowNums.Add(n);
    }
}

我正在和一个同事谈论Linq,他对使用它表示了一些犹豫。他猜测,为了支持Linq所能做的一切,"幕后"可能会发生很多事情。

上述例子之间是否存在显著的性能差异?有没有什么好的资源可以讨论有关集合的LINQ性能?一个简单的搜索linq性能的谷歌发现了一些似乎过时的文章。


Linq的作者在实际中使用for, foreach, List.FindAll做了一些基准测试,Linq查询也做了同样的事情。根据查询的构造方式,Linq只慢了大约10%。正如他们所说的,

LINQ does not come for free.

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

但是,您必须知道不同的查询操作符是如何工作的,因为更改查询流可能会显著地改变它的执行方式。如您所描述的简单查询通常不是问题,但是像Reverse()和转换运算符这样的运算符可能会抛出一些扳手,因为它们需要立即迭代结果集。通常有多种方法可以编写同一个查询,根据构造方式的不同,可以将性能损失降到最低,也可以使其速度比等效循环慢两倍。

不过,它提供的便利性和简洁性远远超过了我日常编码中的任何性能考虑。从不预先优化!


这是我对LINQ的一般规则

Use LINQ when the solution is more expressive. Only switch to a less expressive but faster solution when a profiler has proved that the LINQ query is a source of problem.


有调用委托的开销,但这通常相当低。

然后是所有涉及的迭代器的开销——通常查询中每个额外的子句都有一个迭代器。再说一次,数量不多,但也不算什么。

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

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

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

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


根据LINQ行动(第198页):

"LINQ does not come for free. LINQ
queries cause additional work, object
creations, and pressure on the garbage
collector. The additional cost of
using LINQ can vary a lot depending on
the query. It can be as low as 5
percent, but can sometimes be around
500 percent."


关于linq对对象的真正性能开销,您自己做的事情是为帮助枚举和函数调用而创建的少数额外对象。简而言之,除非你以一种非设计的方式使用它,否则它不会影响你的性能,除非你做的是高性能的东西。

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


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

经常当我对"幕后"究竟发生了什么有疑问时(正如你的同事所想的那样),我会去伊利诺伊州为自己找到答案。我所看到的绝大多数时间,林克的实施是极好的。