推迟执行和急切的评估

你可以给我一个例子,用C#进行急切的评估吗?

我从MSDN读取,推迟执行LINQ可以执行懒惰或渴望评估。 我可以在互联网上find延迟执行与懒惰评估的例子,但我找不到任何示例延迟执行与急切的评价。

而且,延期执行与懒惰评估有什么不同呢? 在我看来,两人看起来都一样。 你能提供一个例子吗?

贝娄是我的回答,但也注意到,Jon Skeet今天在他的博客上谈到了这个事实,即他并不完全符合MSDN的“懒惰”的含义,因为MSDN并不清楚他们使用它在你只是多么懒惰? 他的职位做了一个有趣的阅读。

另外, 维基百科认为应该为延迟评估维护三个规则,第三点在MSDN中不受尊重,因为如果再次调用GetEnumerator ,expression式将被多次评估(由于规范Reset没有对使用yield关键字和linq的大部分目前使用它)


考虑一个function

 int Computation(int index) 

立即执行

 IEnumerable<int> GetComputation(int maxIndex) { var result = new int[maxIndex]; for(int i = 0; i < maxIndex; i++) { result[i] = Computation(i); } return result; } 
  • 当函数被调用时, Computation被执行的maxIndex次数
  • GetEnumerator返回一个新的枚举数实例。
  • MoveNext每次调用都将存储在下一个数组单元格中的值存储在IEnumeratorCurrent成员中,就这些了。

成本 :先期大,枚举小(只有副本)

推迟但急切的执行

 IEnumerable<int> GetComputation(int maxIndex) { var result = new int[maxIndex]; for(int i = 0; i < maxIndex; i++) { result[i] = Computation(i); } foreach(var value in result) { yield return value; } } 
  • 当函数被调用时,会创build一个自动生成的类的实例(在规范中称为“可枚举对象”),实现IEnumerable被创build并且参数的一个副本( maxIndex )被存储在其中。
  • GetEnumerator返回一个新的枚举数实例。
  • MoveNext的第一次调用执行计算方法的maxIndex次,将结果存储在数组中, Current将返回第一个值。
  • 随后对MoveNext每次MoveNext都会将Current存储在数组中的值存入Current值。

成本 :没什么前期的,枚举开始时大,枚举时小(只是一个副本)

延期和懒惰的执行

 IEnumerable<int> GetComputation(int maxIndex) { for(int i = 0; i < maxIndex; i++) { yield return Computation(i); } } 
  • 当这个函数被调用的时候,和懒惰的执行情况一样。
  • GetEnumerator返回一个新的枚举数实例。
  • MoveNext每次调用都会执行一次Computation代码,将该值Current并让调用者立即对结果进行操作。

linq的大部分使用延迟和懒惰执行,但一些函数不能这样sorting。

成本 :没有先期的,枚举中的中等(计算在那里执行)

总结

  • 立即表示计算/执行在函数中完成,并且一旦函数返回完成。 (像大多数C#代码那样完全热切的评估)
  • Deferred / Eager意味着大部分工作将在第一个MoveNext上完成,或者在创buildIEnumerator实例时完成(对于IEnumerable它是在调用GetEnumerator时候)
  • 延迟/ 延迟意味着每次MoveNext都会完成工作,但之前没有任何操作。

并行LINQ的做法有点不同,因为从调用者的angular度来看,计算可以被认为是延迟/懒惰,但是一旦枚举开始,内部计算一些元素就会并行开始。 结果是,如果下一个值已经在那里,你立即得到它,否则你将不得不等待它。

您可以急切地评估延迟执行的IEnumerable的一种方法是使用linq的.ToArray()函数将其简单地转换为数组。

 var evaluated = enumerable.ToArray(); 

这迫使评估完整的枚举,然后你有数组,你可以做任何你想要的。