草庐IT

c# - 延迟执行和急切评估

coder 2024-05-28 原文

你能给我一个在 C# 中使用急切求值的延迟执行的例子吗?

我从 MSDN 了解到,LINQ 中的延迟执行可以通过惰性求值或急切求值来实现。我可以在互联网上找到使用惰性求值的延迟执行的示例,但是我找不到任何使用急切求值的延迟执行的示例。

此外,延迟执行与惰性求值有何不同?在我看来,两者看起来都一样。您能否也为此提供任何示例?

最佳答案

下面是我的回答,但也请注意 Jon Skeet 今天在他的博客上谈到了一个事实,即他对 MSDN 中“懒惰”的含义并不完全满意,因为 MSDN 并不清楚懒惰的确切含义当他们在 Just how lazy are you ? 中使用它时他的帖子值得一读。

另外Wikipedia假设应该为惰性求值维护三个规则,并且在 MSDN 中不遵守第三点,这意味着如果再次调用 GetEnumerator,表达式将被求值不止一次(根据规范 Reset is not implemented on使用 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 都会将存储在下一个数组单元格中的值放入 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;
    }
}
  • 当函数被调用时,自动生成的类(在规范中称为“可枚举对象”)实现 IEnumerable 的实例被创建,并且参数的副本(maxIndex) 存储在其中。
  • GetEnumerator 返回一个新的枚举器实例。
  • 第一次调用 MoveNext 执行计算方法的 maxIndex 次,将结果存储在数组中,Current 将返回第一个值。
  • MoveNext 的每次后续调用都会将存储在数组中的值放入 Current

成本:前期无成本,枚举开始时大,枚举期间小(仅副本)

延迟和惰性执行

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

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

成本:前期无成本,枚举期间适中(计算在那里执行)

总结

  • 立即意味着计算/执行在函数中完成,并在函数返回后完成。 (与大多数 C# 代码一样,完全 eager 评估)
  • 延期/Eager意味着大部分工作将在第一个 MoveNext 或创建 IEnumerator 实例时完成(对于 IEnumerable调用 GetEnumerator)
  • 延期/Lazy意味着每次调用 MoveNext 时都会完成工作,但之前不会。

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

关于c# - 延迟执行和急切评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2515796/

有关c# - 延迟执行和急切评估的更多相关文章

  1. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  2. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  3. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  4. ruby-on-rails - 在所有延迟的作业之前 Hook - 2

    是否可以在所有delayed_job任务之前运行一个方法?基本上,我们试图确保每个运行delayed_job的服务器都有我们代码的最新实例,所以我们想运行一个方法来在每个作业运行之前检查它。(我们已经有了“check”方法并在别处使用它。问题只是关于如何从delayed_job中调用它。) 最佳答案 现在有一种官方方法可以通过插件来做到这一点。这篇博文通过示例清楚地描述了如何执行此操作http://www.salsify.com/blog/delayed-jobs-callbacks-and-hooks-in-rails(本文中描述

  5. ruby - 在 Ruby 中的另一个上下文中评估潜在的相对 URI - 2

    我在Ruby程序中有两个URI。一个肯定是绝对URI,另一个可能是绝对URI或相对URI。我想在第一个的上下文中将第二个转换为绝对URI,所以如果第一个是http://pupeno.com/blog第二个是/about,结果应该是http://pupeno.com/about.有什么想法吗? 最佳答案 Ruby的内置URI和Addressablegem,做这个简短的工作。我更喜欢Addressable,因为它功能更全面,但URI是内置的。require'uri'URI.join('http://pupeno.com/blog','/

  6. ruby - block 内的实例评估 - 2

    我有一个Builder类,可让您添加到其中一个实例变量:classBuilderdefinitialize@lines=[]enddeflinesblock_given??yield(self):@linesenddefadd_line(text)@lines现在,我该如何改变它my_builder=Builder.newmy_builder.lines{|b|b.add_line"foo"b.add_line"bar"}pmy_builder.lines#=>["foo","bar"]进入这个?my_builder=Builder.newmy_builder.lines{add_li

  7. ruby - 使用 autoload 与 ruby​​ 中的 require 进行惰性评估? - 2

    在我的代码中,我使用自动加载进行惰性评估,这样我可以更快地加载程序并在需要时加载文件,我没有看到很多人使用它,但在Thin项目中我注意到自动加载已被广泛使用,反正只是想知道使用它是否有任何风险。 最佳答案 autoload是notthreadsafe并将在未来的Ruby版本中弃用。这是proofbyMatz(ruby的创造者)。 关于ruby-使用autoload与ruby​​中的require进行惰性评估?,我们在StackOverflow上找到一个类似的问题:

  8. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

  9. ruby - 可以像在 C# 中使用#region 一样在 Ruby 中使用 begin/end 吗? - 2

    我最近从C#转向了Ruby,我发现自己无法制作可折叠的标记代码区域。我只是想到做这种事情应该没问题:classExamplebegin#agroupofmethodsdefmethod1..enddefmethod2..endenddefmethod3..endend...但是这样做真的可以吗?method1和method2最终与method3是同一种东西吗?还是有一些我还没有见过的用于执行此操作的Ruby惯用语? 最佳答案 正如其他人所说,这不会改变方法定义。但是,如果要标记方法组,为什么不使用Ruby语义来标记它们呢?您可以使用

  10. c# - Ruby 等效于 C# Linq 聚合方法 - 2

    什么是Linq聚合方法的ruby​​等价物。它的工作原理是这样的varfactorial=new[]{1,2,3,4,5}.Aggregate((acc,i)=>acc*i);每次将数组序列中的值传递给lambda时,变量acc都会累积。 最佳答案 这在数学以及几乎所有编程语言中通常称为折叠。它是更普遍的变形概念的一个实例。Ruby从Smalltalk中继承了这个特性的名称,它被称为inject:into:(像aCollectioninject:aStartValueinto:aBlock一样使用。)所以,在Ruby中,它称为inj

随机推荐