【问题标题】:LINQ PerformanceLINQ 性能
【发布时间】:2009-08-05 05:04:00
【问题描述】:

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

【问题讨论】:

    标签: linq


    【解决方案1】:

    您是指查询表达式,还是查询在后台执行的操作?

    查询表达式首先扩展为“普通”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);
    

    确切的含义取决于source的类型当然...在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);
        }
    }
    

    接下来是将迭代器块扩展为状态机,我不会在这里讨论,但我有一个 article about

    最后,将 lambda 表达式转换为额外的方法 + 适当的委托实例创建(或表达式树,取决于被调用方法的签名)。

    所以基本上 LINQ 使用了 很多 C# 的巧妙功能:

    • Lambda 表达式转换(到委托实例和表达式树)
    • 扩展方法
    • 泛型方法的类型推断
    • 迭代器块
    • 通常是匿名类型(用于投影)
    • 局部变量通常是隐式类型
    • 查询表达式翻译

    但是,单个操作非常简单——它们不执行索引等操作。连接和分组是使用哈希表完成的,但是像“where”这样的简单查询只是线性的。不要忘记 LINQ to Objects 通常只是将数据视为仅向前可读的序列 - 它不能执行二进制搜索之类的操作。

    通常我希望手写查询比 LINQ to Objects 稍微快一点,因为抽象层较少,但它们的可读性会降低,而且性能差异通常不会很大。

    与以往一样,对于性能问题:如有疑问,请衡量!

    【讨论】:

    • 我的意思是它在幕后做了什么。例如,我有一个对象集合。我可以编写一个循环遍历整个集合的 For 循环,并且只检查属性中每个对象中我需要的值,或者我可以使用 LINQ。根据我的阅读,LINQ 在许多情况下似乎更快。我的问题是为什么它更快,它是如何进行查找的?
    • LINQ 通常不会比等效代码快——尽管我相信还有其他项目可以提供索引查找,例如。如果你能给出一个你期望 LINQ 更快的具体例子,那将会很有帮助。
    【解决方案2】:

    如果您需要更好的性能,请考虑尝试 i4o - 对象索引。它为大型集合(想想 100,000+ 行)构建内存对象,然后 LINQ 使用这些对象来加速查询。您需要大量数据才能完成这项工作,但改进令人印象深刻。

    http://www.codeplex.com/i4o

    【讨论】:

      【解决方案3】:

      这只是语法糖 - 没有魔法。

      您可以用“速记”、C# 或其他任何方式写出等效的代码,并且执行相同的代码。

      (当然,编译器会很好地生成高效的代码,所以它生成的代码可能比你自己编写的代码效率高一点,只是因为你可能不知道最高效的编写方式该代码。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-27
        • 1970-01-01
        • 2013-08-04
        • 2011-07-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多