延期执行和急切评估

时间:2010-03-25 13:19:24

标签: c# linq c#-3.0

请您举一个C#中急切评估的延期执行示例?

我从MSDN上读到LINQ中的延迟执行可以通过惰性或急切评估来实现。我可以在互联网上找到延迟执行延迟执行的示例,但是我找不到任何关于延迟执行的示例,并且热切评估。

此外,延迟执行与懒惰评估有何不同?在我看来,两者看起来都一样。你能为此提供任何一个例子吗?

2 个答案:

答案 0 :(得分:44)

贝娄是我的回答,但也注意到Jon Skeet今天在他的博客上谈到了这个事实,即他对MSDN的“懒惰”含义并不完全正确,因为MSDN并不是真正清楚lazy究竟是什么意思当他们在Just how lazy are you ?的帖子中使用它时,可以进行有趣的阅读。

另外Wikipedia假设应该为延迟评估维护三个规则,并且在MSDN中不尊重第三个点,这意味着如果再次调用GetEnumerator,表达式将被多次评估(由spec使用yield关键字生成的枚举器对象上没有实现重置,并且大多数linq当前都使用它


考虑功能

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都会将存储在下一个数据单元格中的值放在Current的{​​{1}}成员中,这就是全部。

费用:大前期,枚举期间小(仅限副本)

延迟但急切的执行

IEnumerator
  • 当调用该函数时,会创建一个自动生成的类的实例(在规范中称为“可枚举对象”),并创建实现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; } } 的参数(IEnumerable)的副本
  • maxIndex返回枚举器的新实例,不再执行任何操作。
  • 第一次调用GetEnumerator执行maxIndex乘以compute方法,将结果存储在数组中,MoveNext将返回第一个值。
  • 每次对Current的调用都会在MoveNext中输入存储在数组中的值。

费用:没有预先设定,枚举开始时为大,枚举期间为小(仅限副本)

延迟执行和延迟执行

Current
  • 当调用函数时,会发生与延迟执行情况相同的事情。
  • IEnumerable<int> GetComputation(int maxIndex) { for(int i = 0; i < maxIndex; i++) { yield return Computation(i); } } 返回枚举器的新实例,不再执行任何操作。
  • 每次调用GetEnumerator都会执行MoveNext代码,将值放入Computation并让调用者立即对结果执行操作。

linq的大多数都使用延迟和延迟执行,但有些函数不能像排序那样。

费用:没有预先设定,在枚举期间适度(计算在那里执行)

总结

  • 立即意味着在函数中完成计算/执行并在函数返回后完成。 (完全eager评估,因为大多数C#代码确实如此)
  • 延迟/ Eager表示大部分工作将在第一个Current或创建MoveNext实例时完成(对于IEnumerator,它是IEnumerableGetEnumerator 1}}被称为)
  • 延期/ Lazy表示每次调用MoveNext时都会完成工作,但之前没有。

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

答案 1 :(得分:1)

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

var evaluated = enumerable.ToArray();

这会强制评估完整的可枚举数,然后你就拥有了你可以做任何你想做的数组。