在linq foreach中调用方法 - 有多少开销?

时间:2010-09-21 12:35:39

标签: c# .net linq performance

我正在考虑用Linq替换很多内联foreach,这样做会产生新的方法,例如: 电流:

foreach(Item in List)
{
    Statement1
    Statement2
    Statement3
}

点子:

List.Foreach(Item => Method(Item))

显然,Method()包含Statement1..3

这是一种好的做法还是数千次调用方法会降低性能?我的名单有10,000-100,000个元素。

4 个答案:

答案 0 :(得分:10)

嗯,首先,您可以使用方法组转换提高ForEach语句的效率

List.ForEach(Method);

这删除了一个间接层。

就个人而言,我认为这不是一个好主意。第一种方法更具可读性,并且可能也可以执行。在这里使用List<T>.ForEach有什么好处?

Eric Lippert在excellent blog post中更多地讨论了这个问题。如果你已经已经有一个你想要针对每个元素执行的委托,我会使用List<T>.ForEach,但我不会为了它而引入委托和额外的方法。

就效率而言,我不希望看到太多差异。第一个表单可能执行得更好,因为它没有委托调用的间接 - 但如果迭代循环在{{{}内,则第二个表单可能更有效1}}利用了它可以访问ForEach的内部数据结构的事实。我非常怀疑你会注意到它。如果你真的很烦,你可以尝试测量它。

答案 1 :(得分:2)

如果你考虑改变的动机是身体中的三个陈述太复杂,那么我可能会使用普通的foreach,但是将身体重构为方法:

foreach(var item in List) 
  Method(item);

如果正文中的代码并不复杂,那么我同意Jon的观点,没有充分的理由使用ForEach(它不会使代码更具可读性/声明性)

我通常不喜欢在LINQ查询结束时使用“LINQ-like”构造来执行命令式处理。我认为使用foreach更清楚地表明您已完成查询数据并且您现在正在进行一些处理。

答案 2 :(得分:1)

我完全赞同Jon Skeet的回答。但既然我们正在谈论ForEach表现,那么我的问题会有所增加。请注意,如果您的声明1~3彼此不相关,那就是:

foreach(Item in List) 
{ 
   DoSomething();
   DoAnotherThing(); 
   DoTheLastThing();
} 

上面的代码可能比以下代码更差:

foreach(Item in List) 
{ 
   DoSomething();
} 
foreach(Item in List) 
{ 
   DoAnotherThing(); 
} 
foreach(Item in List) 
{ 
   DoTheLastThing();
} 

后一个代码需要2个以上的循环具有更好的性能,这是因为当它持续数千次调用DoSomething()时,一些必要的变量在CPU寄存器中总是warm。非常低的成本用于访问这些变量。另一方面,如果在调用DoAnotherThing()后立即调用DoSomthing(),那些已经在CPU寄存器中的DoSomething()变量将会冷却下来。在下一个循环中访问这些变量需要更多的成本。

答案 3 :(得分:0)

我一直认为您应该首先编写代码以便于阅读,因为编译器和CLR在优化时执行例外作业。如果您通过基准测试发现,此代码可以更快地执行,那么请务必查看其他选项。

E.g。 for循环比foreach()快,因为它们使用在CLR内部优化的数组偏移。

但是List.ForEach()肯定不会做foreach(),所以你只是把工作交给另一个方法,而不是自己做。

严格地说,引入更多的方法调用实际上会在第一次传递时减慢代码速度,因为CLR会在调用方法时对JIT进行编译,尽管后续调用方法不会。

所以我的建议是坚持编写可读代码,然后再去那里,如果你能证明这是系统的瓶颈。