迭代Linq结果时出现奇怪的缓慢
在探索最近的Linq问题时,我注意到算法似乎相当慢。 深入挖掘我注意到它不是linq代码,但结果的输出后来耗费了很长时间。 (感谢Marc Gravel顺便说一下,我已经看过了最简单的Linq。)
码:
DateTime dt = DateTime.Now; Console.WriteLine("Alg Start " + dt.Second + "." + dt.Millisecond); var qry = from l in Enumerable.Range(100000, 999999) let s = l.ToString() let sReversed = new string(s.Reverse().ToArray()) from i in Enumerable.Range(3, 9) let t = (l * i).ToString() where t == sReversed select new { l, i }; dt = DateTime.Now; Console.WriteLine("Alg End " + dt.Second + "." + dt.Millisecond); foreach (var row in qry) Console.WriteLine("{0} x {1} = {2}", row.l, row.i, row.l * row.i); dt = DateTime.Now; Console.WriteLine("Disp End " + dt.Second + "." + dt.Millisecond);
输出:
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 to对象中,它只是设置了一堆代理,当你遍历枚举器时会被调用。 如果您要在查询中添加ToList()以实现它,您会看到所花费的时间将转移到设置并远离显示。
linq查询似乎快速执行的原因是因为linq使用延迟执行,所以在定义点上实际上没有计算任何内容,即在您开始枚举结果之前不会执行“实际”工作。
对于许多linq提供程序,只需解析“alg start”到“alt end” – 在实际开始枚举结果之前,不会评估实际表达式。 因此,“qry”变量的实际创建速度很快(只需设置一个实际执行查询中逻辑的枚举),但枚举它的速度较慢。
LINQ代码仅从查询表达式中创建查询对象,这不会花费很多时间。 只有在foreach中才是实际执行的查询。
顺便说一下,你不应该使用DateTime.Now来提高性能,而应该使用Stopwatch类,因为它更准确。
在迭代之前,查询实际上不会计算。 在那之前它就像一个SQL语句,等待执行。
这个问题正在做蛮力; 在这种情况下LINQ实际上非常方便 – 我在这里讨论过: 蛮力(但懒惰)
只是扩展一些以前的答案:
LINQ通常围绕延迟执行进行设计,这意味着在开始迭代结果之前不会发生任何事情。 这通常通过迭代器块完成; 考虑这些之间的区别:
static IEnumerable Where(this IEnumerable data, Func predicate) { foreach(T item in data) { if(predicate(item)) yield return item; } }
和:
static IEnumerable Where(this IEnumerable data, Func predicate) { var list = new List (); foreach(T item in data) { if(predicate(item)) list.Add(item); } return list; }
不同之处在于, 第二个版本在调用Where
时返回所有工作,返回单个结果,其中 – 第二个版本(通过迭代器块的魔法)仅在枚举器调用MoveNext()
时才起作用。 在深度C#的免费样本第6章中更详细地讨论了迭代器块。
通常,这样做的好处是它使查询可组合 – 对于基于数据库的查询尤其重要,但对于常规工作同样有效。
请注意,即使使用迭代器块,还有第二个考虑因素; 缓冲。 考虑Reverse()
– 无论你怎么做,要反转一个序列,首先你需要找到序列的结尾。 现在考虑并非所有序列都结束! 将其与Where
, Skip
, Take
等对比 – 可以在不缓冲的情况下过滤行(只需删除项目)。
在无限序列中使用它的一个很好的例子是这个Fibonacci问题 ,我们可以使用非缓冲的延迟方法:
foreach (long i in Fibonacci().Take(10)) { Console.WriteLine(i); }
没有延迟执行,这将永远不会完成。
上述就是C#学习教程:迭代Linq结果时出现奇怪的缓慢分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1040850.html