延迟执行和急切评估 [英] Deferred execution and eager evaluation

查看:29
本文介绍了延迟执行和急切评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

能否给我举一个在 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 单元格中的值放入 IEnumeratorCurrent 成员中,仅此而已.
    • When the function is called Computation is executed maxIndex 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 the Current member of the IEnumerator 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 and Current will return the first value.
        • Each subsequent call to MoveNext will put in Current 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 the Computation code, put the value in Current and let the caller immediately act on the result.
            • 大多数 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)

              • 立即意味着计算/执行在函数中完成,并在函数返回后完成.(与大多数 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 the IEnumerator instance is created (For IEnumerable it is when GetEnumerator is called)
              • Deferred/Lazy mean that the work will be done each time MoveNext is called but nothing before.

              并行 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆