【问题标题】:Method calls inside LINQ select (efficiency)LINQ select 内部的方法调用(效率)
【发布时间】:2014-01-24 06:49:39
【问题描述】:

我有一个关于 LINQ 与标准 foreach 循环的效率问题。

我有一个方法,大致如下

var foos = users.Select(this.GenerateNullableFoo).Where(foo => foo != null);

结果出于某种原因,速度非常慢。使用时间戳我能够确定缓慢点恰好在 select 的迭代中(从最终返回语句到下一个方法调用开始的时间)比其他任何东西(总时间

当替换为以下时,整个过程时间减少到每次迭代不到 1 秒。

新代码:

var foos= new List<Foo>();

foreach (var user in users)
{
    var foo = GenerateNullableFoo(user);

        foo.IfNotNull(f => foos.Add(foo));
}

据我所知,我的代码可以正常工作,并且新代码没有任何问题,但是,我完全不明白为什么使用上面的 Select 比 foreach 看起来慢 10 倍以上过程。是否有任何关于可能导致这种情况的差异的见解?

此外,直到 说 select/foreach 之后,整个 List 才会保存,此时对 db 进行批量调用。

编辑:从起点到终点(和终止)的整个代码块如下:

//Code snippet pictured above
_repo.SaveFoo(Foos);
//at this point, the code terminates and is finished

【问题讨论】:

  • 您如何使用您的查询?例如,如果您要多次迭代结果,这很容易解释行为。
  • 你试过var foos = users.Select(this.GenerateNullableFoo).Where(foo =&gt; foo != null) .ToList() ;吗?这将创建更类似于foreach 的代码。
  • 为什么上面有foo != null,下面有foo.IfNotNull(..)
  • 这两个不是等价的。第二个构建一个列表,第一个创建一个 IEnumerable。正如其他 cmets 指出的那样,多次使用第一个结果将导致多次执行。该列表将在后续使用中简单地遍历集合
  • 我不确定我的代码将如何多次使用选择的结果。这些 sn-ps 之后的唯一代码是批量保存 _repo.SaveAll(Foos);然后代码完成并完全终止该过程。 @蒂姆。 where 子句作用于生成的 foo 以确保它不为空,这与底部 IfNotNull 子句中所做的相同。这两个项目都只是检查“如果 foo 不为空,则将其保留在列表中/将其添加到列表中”

标签: c# asp.net linq foreach performance


【解决方案1】:

正如其他人所说,LINQ 表达式在被代码迭代之前不会投影到结果集,这意味着您所做的只是声明逻辑。

发布的代码会导致 LINQ 表达式被投影,而且很可能会被投影很多次。

解决这个问题的最短方法是简单地将 .ToList() 添加到您的表达式中,这将立即投影表达式,这意味着其他代码可以使用内存中的和已经投影的列表,而不会导致额外的投影/计算/等等等等。

干杯,亚伦

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-26
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多