简介
Linq中的绝大多数查询运算符都有延迟执行的特性,查询并不是在查询创建的时候执行,而是在遍历的时候执行
实例:
public void Test2(){List<int> items = new List<int>() { -1, 1, 3, 5 };IEnumerable<int> items2 = items.Where(x => x > 0);foreach (int item in items2){Console.WriteLine(item);}items.Add(40);Console.WriteLine("----------------");foreach (int item in items2){Console.WriteLine(item);}Console.WriteLine("*****************");}
运行结果:
可以看到,执行结果也验证上述的说明,查询创建后,并没有马上执行,而是在遍历对象时才执行,否则第二个遍历不会打印出40.
如果在查询后面添加ToList等转换符,则会立即执行,如
IEnumerable<int> items2 = items.Where(x => x > 0).ToList();
扩展1
上面我们使用时LINQ的API语法,还有一种时查询语法,上面的语句可以改写为:
IEnumerable<int> items3 = from n in itemswhere n > 0select n;foreach (int item in items3)
{Console.WriteLine(item);
}
两种方案区别不大。唯一的区别查询语法允许使用 let 子句,这样,便可以在表达式的作用域内引入和绑定变量,然后在表达式的后续片段中使用该变量。 只使用 API 语法重现相同的代码也是可行的,不过,这很可能会导致代码难以阅读。
扩展2
PLINQ(又称并行 LINQ)是 LINQ 表达式的并行执行引擎。 换言之,LINQ 正则表达式可能会没有意义地在任意数量的线程之间并行化。 为此,可以调用表达式前面的 AsParallel()
上面的代码可以做一下扩展使用并行库执行
IEnumerable<int> items2 = items.AsParallel().Where(x => x > 0);
实例:
Stopwatch stopwatch = new Stopwatch();public void TestPLINQ(){stopwatch.Restart();IEnumerable<int> numbers = Enumerable.Range(3, 10000000 - 3);var parallelQuery =from n in numbers.AsParallel()where Enumerable.Range(2, (int)Math.Sqrt(n)).All(i => n % i > 0)select n;int[] primes = parallelQuery.ToArray();Console.WriteLine("PLINQ 耗时:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");stopwatch.Stop();}public void TestLINQ(){stopwatch.Restart();IEnumerable<int> numbers = Enumerable.Range(3, 10000000 - 3);var parallelQuery =from n in numbers//AsParallel()where Enumerable.Range(2, (int)Math.Sqrt(n)).All(i => n % i > 0)select n;int[] primes = parallelQuery.ToArray();Console.WriteLine("LINQ 耗时:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");stopwatch.Stop();}
执行结果:
可以看到,对于CPU密集型任务,使用PLINQ执行的效率有明显提升。