lambda与第一个lambda的关系

mic*_*ver 8 .net linq c#-3.0

假设我有一些字符串:

string[] strings = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
Run Code Online (Sandbox Code Playgroud)

有什么区别:

string startsWithO = strings.First(s => s[0] == 'o');
Run Code Online (Sandbox Code Playgroud)

和:

string startsWithO = strings.Where(s => s[0] == 'o').First();
Run Code Online (Sandbox Code Playgroud)

由于Where()被推迟,它不应该减慢执行速度,对吗?

Eam*_*nne 12

使用.Where(filter).First()而不是.First(filter)通常会非常小的性能损失.

然而,它们并不相同 - Where生成一个新的迭代器,它First可以简单地取一个元素,而First(filter)可以通过只使用一个循环进行微优化,并在filter匹配时直接返回.

因此,尽管这两种方法具有相同的语义和两者执行filter同样经常(仅视需要经常),使用First带有filter参数并不需要创建一个中间迭代器对象,并可能避免了一些很简单的方法对迭代器调用了.

换句话说,如果你执行这样的代码数百万次,你会看到一个轻微的性能差异 - 但没有什么大的; 我永远不会担心它.每当这个微小的性能差异真正重要时,你只需要编写(非常简单的)foreach-with-if语句就可以了,这种语句相当于避免LINQ中固有的额外调用和对象分配 - 但请记住,这是一个微观优化你会很少需要.

编辑:基准证明效果:

这需要0.78秒:

for(int i=0;i<10*1000*1000;i++)
  Enumerable.Range(0,1000).First(n=> n > 2);
GC.Collect();
Run Code Online (Sandbox Code Playgroud)

但这需要1.41秒:

for(int i=0;i<10*1000*1000;i++)
  Enumerable.Range(0,1000).Where(n=> n > 2).First();
GC.Collect();
Run Code Online (Sandbox Code Playgroud)

而普通循环要快得多(0.13秒):

long bla = 0;
for(int i=0;i<10*1000*1000;i++)
    for(int n=0;n<1000;n++)
        if(n > 2) { bla+=n; break; }
GC.Collect();
Console.WriteLine(bla);//avoid optimizer cheating.
Run Code Online (Sandbox Code Playgroud)

请注意,此基准测试仅显示如此极端的差异,因为我有一个简单的过滤器和一个非常短的非匹配前缀.

基于一些快速实验,差异似乎主要归因于获取代码路径的细节.因此,对于数组和List<>s,第一个变体实际上更快,可能.Where为那些没有的类型做特殊套管First; 对于自定义迭代器,第二个版本比预期的要快一点.

摘要:

.Where(...).First()与...一样快 .First(...)- 不要费心选择其中一个作为优化.在一般 .First(...)非常稍快,但在某些常见的情况是比较慢.如果你真的需要微优化,那么使用比任何一个都快的普通循环.