延迟执行和急切评估 [英] Deferred execution and eager evaluation
问题描述
能否给我举一个在 C# 中使用 Eager 求值的延迟执行示例?
Could you please give me an example for Deferred execution with eager evaluation in C#?
我从 MSDN 上读到,LINQ 中的延迟执行可以通过惰性求值或急切求值来实现.我可以在互联网上找到延迟执行延迟执行的示例,但是我找不到任何延迟执行延迟执行的示例.
I read from MSDN that deferred execution in LINQ can be implemented either with lazy or eager evaluation. I could find examples in the internet for Deferred execution with lazy evaluation, however I could not find any example for Deferred execution with eager evaluation.
此外,延迟执行与惰性求值有何不同?在我看来,两者看起来都一样.您能否也提供任何示例?
Moreover, how deferred execution differs from lazy evaluation? In my point of view, both are looking same. Could you please provide any example for this too?
推荐答案
Bellow 是我的回答,但也请注意 Jon Skeet 今天在他的博客上谈到了这个事实,他对 MSDN 中的意思"并不完全满意Lazy",因为 MSDN 在 你有多懒?他的帖子读起来很有趣.
Bellow is my answer but also note that Jon Skeet spoke about it today on his blog an about the fact that he is not totally ok with the MSDN meaning of "Lazy" as MSDN isn't really clear of what lazy exactly mean when they use it in Just how lazy are you ? his post make for an interesting read.
另外维基百科假设应该为惰性求值维护三个规则,而第三点不是在 MSDN 中,这意味着如果 GetEnumerator
再次被调用,表达式将被评估不止一次(根据规范,Reset 不会在使用 yield
关键字生成的枚举器对象上实现,并且大多数的 linq 目前使用它)
Additionally Wikipedia assume that three rules should be maintained for lazy evaluation and third point isn't respected in MSDN meaning as the expression will be evaluated more than once if GetEnumerator
is called again (By the spec Reset is not implemented on enumerator objects generated using the yield
keyword and most of linq use it currently)
考虑一个函数
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
都会将存储在下一个 Array 单元格中的值放入IEnumerator
的Current
成员中,仅此而已. - When the function is called
Computation
is executedmaxIndex
times GetEnumerator
returns a new instance of the enumerator doing nothing more.- Each call to
MoveNext
put the the value stored in the next Array cell in theCurrent
member of theIEnumerator
and that's all.
成本:前期大,枚举期间小(只有一个副本)
Cost: Big upfront, Small during enumeration (only a copy)
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
返回一个新的枚举器实例,仅此而已.- 第一次调用
MoveNext
执行计算方法的 maxIndex 倍,将结果存储在一个数组中,Current
将返回第一个值. - 每次对
MoveNext
的后续调用都会在Current
中放入一个存储在数组中的值. - When the function is called an instance of an auto generated class (called "enumerable object" in the spec) implementing
IEnumerable
is created and a copy of the argument (maxIndex
) is stored in it. GetEnumerator
returns a new instance of the enumerator doing nothing more.- The first call to
MoveNext
executes maxIndex times the compute method, store the result in an array andCurrent
will return the first value. - Each subsequent call to
MoveNext
will put inCurrent
a value stored in the array.
成本:前期没有,枚举开始时大,枚举时小(只有一个副本)
Cost: nothing upfront, Big when the enumeration start, Small during enumeration (only a copy)
IEnumerable<int> GetComputation(int maxIndex)
{
for(int i = 0; i < maxIndex; i++)
{
yield return Computation(i);
}
}
- 当函数被调用时,发生与惰性执行情况相同的事情.
GetEnumerator
返回一个新的枚举器实例,仅此而已.- 对
MoveNext
的每次调用都会执行一次Computation
代码,将值放入Current
并让调用者立即对结果采取行动. - When the function is called the same thing as the lazy execution case happens.
GetEnumerator
returns a new instance of the enumerator doing nothing more.- Each call to
MoveNext
execute once theComputation
code, put the value inCurrent
and let the caller immediately act on the result. - 立即意味着计算/执行在函数中完成,并在函数返回后完成.(与大多数 C# 代码一样,完全急切 评估)
- Deferred/Eager 意味着大部分工作将在第一个
上完成MoveNext
或当IEnumerator
实例被创建时(对于IEnumerable
是在GetEnumerator
被调用时) - Deferred/Lazy 表示每次
MoveNext都会完成工作code> 被调用,但之前什么也没调用.
- Immediate mean that the computation/execution is done in the function and finished once the function return. (Fully eager evaluation as most C# code does)
- Deferred/Eager mean that most of the work will be done on the first
MoveNext
or when theIEnumerator
instance is created (ForIEnumerable
it is whenGetEnumerator
is called) - Deferred/Lazy mean that the work will be done each time
MoveNext
is called but nothing before.
大多数 linq 使用延迟和延迟执行,但有些功能不能像排序一样.
Most of linq use deferred and lazy execution but some functions can't be so like sorting.
成本:没有任何前期费用,枚举期间适中(计算在那里执行)
Cost: nothing upfront, Moderate during enumeration (the computation is executed there)
并行 LINQ 的做法略有不同,因为计算可以被视为延迟/延迟从调用者的角度来看,但在内部,一旦枚举开始,一些元素的计算就会并行开始.结果是,如果下一个值已经存在,您会立即获得它,否则您将不得不等待它.
Parallel LINQ does it a little differently as the computation could be considered deferred/Lazy from the point of view of the caller but internally the computation of some number of elements begin in parallel as soon as the enumeration begin. The result is that if the next value is already there you get it immediately but otherwise you will have to wait for it.
这篇关于延迟执行和急切评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!