C# 在Linq结果上迭代时出现奇怪的慢度
在研究最近的一个问题时,我注意到算法似乎相当慢。深入挖掘,我注意到花费了很长时间的不是linq代码,而是结果的输出。(顺便说一句,马克·格拉斯踢出了我见过的最光滑的林克,这是我的荣幸。) 代码:C# 在Linq结果上迭代时出现奇怪的慢度,c#,linq,C#,Linq,在研究最近的一个问题时,我注意到算法似乎相当慢。深入挖掘,我注意到花费了很长时间的不是linq代码,而是结果的输出。(顺便说一句,马克·格拉斯踢出了我见过的最光滑的林克,这是我的荣幸。) 代码: 输出: Alg Start 20.257 Alg End 20.270 109989 x 9 = 989901 219978 x 4 = 879912 1099989 x 9 = 9899901 Disp End 31.322 .13秒计算,超过11秒显示?!?原因是什么?linq查询看起来执
输出:
Alg Start 20.257
Alg End 20.270
109989 x 9 = 989901
219978 x 4 = 879912
1099989 x 9 = 9899901
Disp End 31.322
.13秒计算,超过11秒显示?!?原因是什么?linq查询看起来执行得很快的原因是,在定义点上实际上没有计算任何内容,因为linq使用延迟执行,即,在开始枚举结果之前,不会执行任何“实际”工作。原因是,在枚举结果之前,查询不会实际运行。在LINQto对象中,它只设置一组委托,当您迭代枚举器时,这些委托将被调用。如果要向查询中添加ToList()来具体化它,您将看到所花费的时间将转移到设置和远离显示。对于许多linq提供程序,“alg start”到“alt end”只是解析而已-实际表达式在您实际开始枚举结果之前不会计算。因此,“qry”变量的实际创建速度很快(只需设置一个实际执行查询逻辑的可枚举项),但通过该变量进行枚举的速度较慢。LINQ代码只在查询表达式之外创建一个查询对象,这不会占用很多时间。只有在foreach中才实际执行查询
顺便说一句,您不应该使用DateTime.Now进行性能计时,但是使用Stopwatch类,因为它更精确。在您迭代查询之前,查询实际上不会计算。在此之前,它就像一个SQL语句,等待执行。这个问题是在进行暴力强迫;在这种情况下,LINQ实际上非常方便——我在这里讨论了这一点: 仅对前面的一些答案进行扩展: LINQ通常是围绕延迟执行而设计的,这意味着在开始迭代结果之前不会发生任何事情。这通常通过迭代器块完成;考虑这些之间的差异:
static IEnumerable<T> Where(this IEnumerable<T> data, Func<T,bool> predicate) {
foreach(T item in data) {
if(predicate(item)) yield return item;
}
}
如果没有延迟执行,这将永远不会完成。请记住:查询表达式的结果是查询,而不是查询的结果。在向查询请求结果之前,您不会得到查询结果;我稍后发布的版本应该更快。。。但是延迟执行是这里的关键。
static IEnumerable<T> Where(this IEnumerable<T> data, Func<T,bool> predicate) {
foreach(T item in data) {
if(predicate(item)) yield return item;
}
}
static IEnumerable<T> Where(this IEnumerable<T> data, Func<T,bool> predicate) {
var list = new List<T>();
foreach(T item in data) {
if(predicate(item)) list.Add(item);
}
return list;
}
foreach (long i in Fibonacci().Take(10)) {
Console.WriteLine(i);
}