LINQ性能

4

在针对对象集合的LINQ查询背后,究竟发生了什么?它只是语法糖吗,还是有其他的事情发生,使得它成为更高效的查询?

3个回答

12

您是指查询表达式,还是查询背后的操作?

查询表达式首先会被扩展为“正常”的C#代码。例如:

var query = from x in source
            where x.Name == "Fred"
            select x.Age;

被翻译成:

var query = source.Where(x => x.Name == "Fred")
                  .Select(x => x.Age);

这取决于所涉及的源类型的确切含义,比如在LINQ to Objects中,它通常实现了"IEnumerable<T>",并使用"Enumerable"扩展方法...但也可能是不同的扩展方法集合。(例如,LINQ to SQL将使用"Queryable"扩展方法。)
现在,假设我们正在使用LINQ to Objects... 扩展方法展开后,上述代码变成了:
var query = Enumerable.Select(Enumerable.Where(source, x => x.Name == "Fred"),
                              x => x.Age);

接下来,SelectWhere的实现变得很重要。不考虑错误检查,它们大致是这样的:

public static IEnumerable<T> Where<T>(this IEnumerable<T> source,
                                      Func<T, bool> predicate)
{
    foreach (T element in source)
    {
        if (predicate(element))
        {
            yield return element;
        }
    }
}

public static IEnumerable<TResult> Select<TSource, TResult>
    (this IEnumerable<TSource> source,
     Func<TSource, TResult> selector)
{
    foreach (TSource element in source)
    {
        yield return selector(element);
    }
}

下一步是将迭代器块扩展为状态机,我不会在这里进行详细解释,但我有一篇关于此的文章
最后,就是将lambda表达式转换为额外的方法+适当的委托实例创建(或表达式树,取决于调用的方法的签名)。
因此,基本上LINQ使用了C#的很多巧妙特性:
- Lambda表达式转换(成委托实例和表达式树) - 扩展方法 - 泛型方法的类型推断 - 迭代器块 - 通常使用匿名类型(用于投影) - 通常使用隐式类型定义局部变量 - 查询表达式转换
然而,这些单独的操作非常简单 - 它们不执行索引等操作。连接和分组使用哈希表完成,但像“where”这样的简单查询只是线性的。请勿忘记,LINQ to Objects通常只将数据视为仅向前可读的序列 - 它不能执行二进制搜索等操作。
通常情况下,我期望手写查询比LINQ to Objects稍微快一点,因为它们没有那么多层抽象,但它们将更难以阅读,并且性能差异通常不会很大。
对于性能问题,一如既往:如果有疑问,请进行测量!

我的意思是它在幕后做了什么。例如,我有一个对象集合。我可以编写一个For循环来遍历整个集合,并仅检查每个对象中所需的值的属性,或者我可以使用LINQ。根据我所读到的,LINQ在许多情况下似乎更快。我的问题是为什么它更快,以及它如何执行查找? - Crios
LINQ通常不会比等效的代码更快 - 尽管我相信还有其他项目提供索引查找,例如。如果您能给出一个具体的例子,您期望LINQ更快,那将非常有帮助。 - Jon Skeet

3
如果您需要更好的性能,请考虑尝试 i4o - 对象索引。它为大型集合(想象一下100,000+行)建立内存对象,然后LINQ使用它来加速查询。您需要大量数据才能使其工作,但改进效果令人印象深刻。 http://www.codeplex.com/i4o

2

这只是一种语法糖,其中没有涉及到任何魔法。

你可以用"C#"或其他语言手写等效的代码,它们将会执行相同的功能。

(当然,编译器会生成高效的代码,所以它生成的代码可能比你自己写的代码更加高效,因为你可能不知道如何编写最有效的代码。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接