λ J*_*kas 11 c# linq compiler-construction optimization list-comprehension
考虑以下C#代码:
IEnumerable numbers = Enumerable.Range(0, 10);
var evens = from num in numbers where num % 2 == 0 select num;
Run Code Online (Sandbox Code Playgroud)
这是一个纯粹的语法糖,允许我写一个for或foreach循环作为一个班轮?是否有任何编译器优化使得上面的列表理解比循环结构更有效?这是如何工作的?
Mat*_*hen 14
正如杰森所说,你的代码相当于:
Enumerable.Range(0, 10).Where(n => n % 2 == 0);
Run Code Online (Sandbox Code Playgroud)
请注意,lambda将转换为函数调用,该函数调用是针对每个元素完成的.这可能是开销的最大部分.我做了一个测试,这表明LINQ在这个确切的任务上慢了3倍(mono gmcs version 1.2.6.0)
Time for 10000000 for loop reps: 00:00:17.6852560
Time for 10000000 LINQ reps: 00:00:59.0574430
Time for 1000000 for loop reps: 00:00:01.7671640
Time for 1000000 LINQ reps: 00:00:05.8868350
编辑:Gishu报告VS2008和框架v3.5 SP1给出:
Time for 1000000 loop reps: :00.3724585
Time for 1000000 LINQ reps: :00.5119530
LINQ大约慢了1.4倍.
它将for循环和列表与LINQ(以及它在内部使用的任何结构)进行比较.无论哪种方式,它将结果转换为数组(迫使LINQ停止"懒惰").两个版本重复:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
public class Evens
{
private static readonly int[] numbers = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
private static int MAX_REPS = 1000000;
public static void Main()
{
Stopwatch watch = new Stopwatch();
watch.Start();
for(int reps = 0; reps < MAX_REPS; reps++)
{
List<int> list = new List<int>(); // This could be optimized with a default size, but we'll skip that.
for(int i = 0; i < numbers.Length; i++)
{
int number = numbers[i];
if(number % 2 == 0)
list.Add(number);
}
int[] evensArray = list.ToArray();
}
watch.Stop();
Console.WriteLine("Time for {0} for loop reps: {1}", MAX_REPS, watch.Elapsed);
watch.Reset();
watch.Start();
for(int reps = 0; reps < MAX_REPS; reps++)
{
var evens = from num in numbers where num % 2 == 0 select num;
int[] evensArray = evens.ToArray();
}
watch.Stop();
Console.WriteLine("Time for {0} LINQ reps: {1}", MAX_REPS, watch.Elapsed);
}
}
Run Code Online (Sandbox Code Playgroud)
过去对类似任务的性能测试(例如LINQ vs Loop - 性能测试)证实了这一点.
您可以进一步简化代码
var evens = Enumerable.Range(0, 10).Where(n => n % 2 == 0);
Run Code Online (Sandbox Code Playgroud)
此形式的一个优点是延迟执行此表达式,直到evens迭代遍历(foreach(var n in evens) { ... }).上面的语句只是告诉编译器捕获如何枚举0到10之间的偶数的想法,但是在绝对必要之前不执行该想法.