【问题标题】:Does breaking chained Select()s in LINQ to objects hurt performance?将 LINQ 中的链式 Select() 断开到对象是否会损害性能?
【发布时间】:2010-05-04 05:13:17
【问题描述】:

获取以下伪 C# 代码:

using System;
using System.Data;
using System.Linq;
using System.Collections.Generic;

public IEnumerable<IDataRecord> GetRecords(string sql)
{
     // DB logic goes here
}

public IEnumerable<IEmployer> Employers()
{
     string sql = "select EmployerID from employer";
     var ids = GetRecords(sql).Select(record => (record["EmployerID"] as int?) ?? 0);
     return ids.Select(employerID => new Employer(employerID) as IEmployer);
}

如果合并两个 Select() 调用会更快吗?上面的代码中是否有额外的迭代?下面的代码更快吗?

public IEnumerable<IEmployer> Employers()
{
     string sql = "select EmployerID from employer";
     return GetRecords(sql).Select(record => new Employer((record["EmployerID"] as int?) ?? 0) as IEmployer);
}

如果性能没有差异,我认为第一个示例更具可读性。

【问题讨论】:

  • 这两个代码sn-ps真的一样吗?一个有GetRecords(sql),另一个有Query.Records(sql)...
  • @Jeremy - 他们应该是一样的 - 这是我的错字

标签: .net performance linq-to-objects readability


【解决方案1】:

没有显着差异。两种方法都返回一个表达式,该表达式可以遍历 GetRecords 的结果。

它们并不相同,因为第一个链接了 Select,但它们仍然会以相同的顺序执行相同的工作。当循环链接的 Selects 时,第二个 select 将根据需要从第一个 Select 中放置一个和一个项目,第一个 Select 不必在第二个 Select 可以使用结果之前完成。

【讨论】:

  • 这听起来像链式选择我有两个小状态机,一个传递给另一个。与一体机相比,这不会增加任何显着的内存开销吗?
  • @Justin:是的,他们每个人都有自己的枚举器(或类似的状态),所以在处理过程中会有一点开销,但是从 GetRecords 结果开始,这些项目仍然是一个又一个地处理,所以内存中没有积累。与从数据库中获取数据所需的时间相比,额外的开销可以忽略不计。
【解决方案2】:

没有区别。

LINQ 使用延迟评估的思想,source。我将引用相关部分:

为了解决这个问题,所有内置的 LINQ 提供程序都使用了一个称为延迟执行的概念。不是让查询运算符立即执行,它们都简单地返回实现 IEnumerable(of T) 接口的类型。然后,这些类型会延迟执行,直到在 for each 循环中实际使用查询。

基本上,直到您在foreach.ToList() 等中使用Employers() 的结果,它实际上并没有做任何工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 2014-06-17
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2013-08-15
    相关资源
    最近更新 更多