我打算用Linq替换很多内联的foreach,并在这样做的过程中创建新的方法,例如:
当前代码:
foreach(Item in List)
{
Statement1
Statement2
Statement3
}
想法:
List.Foreach(Item => Method(Item))
很明显,Method() 包含 Statement1..3。
这是一个好习惯吗?还是调用方法数千次会降低性能?我的列表有10,000-100,000个元素。
我打算用Linq替换很多内联的foreach,并在这样做的过程中创建新的方法,例如:
当前代码:
foreach(Item in List)
{
Statement1
Statement2
Statement3
}
想法:
List.Foreach(Item => Method(Item))
很明显,Method() 包含 Statement1..3。
这是一个好习惯吗?还是调用方法数千次会降低性能?我的列表有10,000-100,000个元素。
嗯,首先你可以使用方法组转换使得ForEach
语句更加高效。
List.ForEach(Method);
这样就减少了一级间接性。
但是,我个人认为这不是一个好主意。第一种方法更易读,并且可能表现得和第二种方式差不多。使用 List<T>.ForEach
的优势是什么?
Eric Lippert 在一篇精彩的博客文章中更详细地讨论了这个问题。如果你已经有一个要对每个元素执行的委托,那么我会使用List<T>.ForEach
,但我不会为了这个目的引入委托和额外的方法。
就效率而言,我不指望会看到很大的区别。第一种形式可能表现得更好,因为它没有委托调用的间接性 - 但如果 ForEach
中的迭代循环利用了对 List<T>
的内部数据结构的访问权,则第二种形式可能更有效。我非常怀疑你会注意到任何一种方式。当然,如果你真的在意,你可以尝试进行测量。
List<T>
的各种方法进行了相当广泛的性能比较。希望这有所帮助。 :) http://msmvps.com/blogs/jon_skeet/archive/2006/01/20/foreachperf.aspx - Anibutton.Click += ClickHandler;
这样的操作。 - Jon Skeet如果你考虑更改的原因是循环体中的三个语句太复杂,那么我可能会使用普通的foreach
,但重构循环体为一个方法:
foreach(var item in List)
Method(item);
我完全同意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();
}
后者的代码需要多循环两次,但性能更好的原因是,当它不断调用DoSomething()数千次时,一些必要的变量始终在CPU寄存器中处于“热”状态。访问这些变量的成本非常低。另一方面,如果它在调用DoSomthing()之后立即调用DoAnotherThing(),那么已经在CPU寄存器中的DoSomething()变量将会冷却下来。在下一个循环中,访问这些变量需要更高的成本。
我一直认为,你应该首先为可读性编写代码,因为编译器和CLR在优化方面做得非常出色。如果你发现通过基准测试,这段代码可以更快地执行,那么可以考虑其他选项。
例如,for循环比foreach()更快,因为它们使用数组偏移量,在CLR内部进行了优化。
但是,List.ForEach()肯定会执行foreach(),所以你只是把工作交给了另一个方法,而不是自己去做。
严格来说,引入更多的方法调用实际上会在第一次通过时减慢代码的速度,因为CLR将在调用方法时JIT编译方法,尽管对该方法的后续调用不会这样做。
因此,我的建议是坚持编写易读的代码,如果你能证明这是系统的瓶颈,再从那里开始。