向 C# 添加“lazy”关键字时出现的问题

2024-01-18

我很想写这样的代码:

class Zebra
{
    public lazy int StripeCount
    {
        get { return ExpensiveCountingMethodThatReallyOnlyNeedsToBeRunOnce(); }
    }
}

编辑:为什么?我认为它看起来比:

class Zebra
{
    private Lazy<int> _StripeCount;

    public Zebra()
    {
        this._StripeCount = new Lazy(() => ExpensiveCountingMethodThatReallyOnlyNeedsToBeRunOnce());
    }

    public lazy int StripeCount
    {
        get { return this._StripeCount.Value; }
    }
}

第一次调用该属性时,它将运行get块,然后只返回其中的值。

我的问题:

  1. 将此类关键字添加到库中会涉及哪些成本?
  2. 在什么情况下这会出现问题?
  3. 你觉得这有用吗?

我并不是要发起一场运动,将其纳入到库的下一版本中,但我很好奇像这样的功能应该经过什么样的考虑。


我很好奇这样的功能应该经过什么样的考虑。

首先,我写了一篇关于这个主题的博客。请参阅我的旧博客:

http://blogs.msdn.com/b/ericlippert/ http://blogs.msdn.com/b/ericlippert/

和我的新博客:

http://ericlippert.com http://ericlippert.com

关于语言设计各个方面的许多文章。

其次,C# 设计过程现已向公众开放,因此您可以亲自了解语言设计团队在审查新功能建议时的考虑因素。看https://github.com/dotnet/roslyn/ https://github.com/dotnet/roslyn/了解详情。

将此类关键字添加到库中会涉及哪些成本?

这取决于很多事情。当然,不存在廉价、简单的功能。只有更便宜、更简单的功能。一般来说,成本是涉及设计、指定、实施、测试、记录和维护功能的成本。还有更多奇特的成本,例如不做更好的功能的机会成本,或者选择与我们可能想要添加的未来功能交互不良的功能的成本。

在这种情况下,该功能可能只是简单地使“lazy”关键字成为使用的语法糖Lazy<T>。这是一个非常简单的功能,不需要大量花哨的语法或语义分析。

在什么情况下这会出现问题?

我可以想到很多因素会导致我拒绝该功能。

首先,没有必要;它只是一种方便的糖。它并没有真正为该语言增添新的力量。所带来的好处似乎不值得所付出的代价。

其次,也是更重要的一点,它体现了特别的对语言的一种懒惰。懒惰有不止一种,我们可能会选择错误。

怎么会有不止一种懒惰呢?好吧,想想如何实施。属性已经是“惰性的”,因为它们的值在调用该属性之前不会计算,但您想要的不止于此;您想要一个被调用一次的属性,然后该值将被缓存以供下次调用。 “惰性”本质上是指记忆属性。我们需要做出哪些保证?有很多种可能性:

可能性#1:根本不是线程安全的。如果您在两个不同的线程上“第一次”调用该属性,则任何事情都可能发生。如果你想避免竞争条件,你必须自己添加同步。

可能性#2:线程安全,这样两个不同线程上对属性的两次调用都调用初始化函数,然后竞相查看谁填充了缓存中的实际值。据推测,该函数将在两个线程上返回相同的值,因此这里的额外成本仅在于浪费的额外调用。但缓存是线程安全的,不会阻塞任何线程。 (因为线程安全缓存可以用低锁或无锁代码编写。)

实现线程安全的代码是有代价的,即使它是低锁代码。这个成本可以接受吗?大多数人编写的都是有效的单线程程序;无论是否需要,将线程安全的开销添加到每个惰性属性调用中似乎是正确的吗?

情况#3:线程安全,有力保证初始化函数只会被调用一次;缓存上没有竞争。用户可能隐含地期望初始化函数只被调用一次;它可能非常昂贵,并且两个不同线程上的两次调用可能是不可接受的。实现这种惰性需要完全同步,其中一个线程可能会无限期地阻塞,而惰性方法正在另一个线程上运行。这也意味着如果惰性方法存在锁顺序问题,则可能会出现死锁。

这甚至增加了该功能的成本,而使用该功能的人同样承担这一成本not利用它(因为他们正在编写单线程程序)。

那么我们该如何处理这个问题呢?我们可以添加三个功能:“惰性非线程安全”、“具有竞争的惰性线程安全”和“具有阻塞和可能死锁的惰性线程安全”。现在这个功能变得更加昂贵并且way更难记录。这会产生一个enormous用户教育问题。每次你给开发人员这样的选择时,你就为他们提供了编写可怕错误的机会。

第三,正如所述,该功能似乎很弱。为什么惰性应该仅仅应用于属性?看起来这可以通过类型系统普遍应用:

lazy int x = M(); // doesn't call M()
lazy int y = x + x; // doesn't add x + x
int z = y * y; // now M() is called once and cached.
               // x + x is computed and cached
               // y * y is computed

如果有一个更通用的功能是它的自然扩展,我们会尽量不做小的、弱的功能。但现在我们谈论的是非常严重的设计和实施成本。

你觉得这有用吗?

亲自?不太有用。我编写了大量简单的低锁惰性代码,主要使用 Interlocked.Exchange。 (我不在乎惰性方法是否运行两次并且其中一个结果被丢弃;我的惰性方法从来没有那么昂贵。)该模式很简单,我知道它是安全的,永远不会为委托分配额外的对象或者锁,如果我有更复杂的东西,我总是可以使用Lazy<T>为我做工作。这将是一个小小的便利。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

向 C# 添加“lazy”关键字时出现的问题 的相关文章

  • 数据模板绑定垃圾邮件输出窗口出现错误:找不到管理 FrameworkElemen

    我有问题 System Windows Data 错误 2 找不到目标元素的管理 FrameworkElement 或 FrameworkContentElement BindingExpression 无路径 数据项 空 目标元素是 So
  • 在 C/C++ 中获得正模数的最快方法

    通常在我的内部循环中 我需要以 环绕 方式索引数组 因此 例如 如果数组大小为 100 并且我的代码要求元素 2 则应该给它元素 98 高级语言 例如 Python 可以简单地使用my array index array size 但由于某
  • 平滑滚动.net 表单

    您好 我正在 net 中使用表单 并且在运行时动态添加大量链接标签 我将这些链接标签添加到面板并将该面板添加到 winform 当链接标签的数量增加时 表单会显示一个自动滚动条 垂直 现在 当我使用自动滚动向下滚动时 表单在滚动时不会更新其
  • 防止 boost::asio::io_context 在空轮询调用时停止

    此代码调用发布的句柄 boost asio io context ioc boost asio post ioc std cout lt lt lol lt lt std endl ioc poll 而这并没有 boost asio io
  • 如何在 SqlDataReader.Read() 期间从死锁异常中恢复

    我的 NET 应用程序的事件日志显示 它在从 Sql Server 读取数据时偶尔会出现死锁 这种情况通常非常罕见 因为我们已经优化了查询以避免死锁 但有时仍然会发生 过去 我们在调用ExecuteReader函数在我们的SqlComman
  • 指向特征矩阵的指针数组

    我在代码中使用 Eigen 的 MatrixXd 矩阵 在某个时刻我需要一个 3D 矩阵 由于 Eigen 没有三维矩阵类型 因为它仅针对线性代数进行了优化 因此我创建了一个 MatrixXd 类型的指针数组 Eigen MatrixXd
  • ASP.Net Core 内容配置附件/内联

    我正在从 WebAPI 控制器返回一个文件 Content Disposition 标头值自动设置为 附件 例如 处置 附件 文件名 30956 pdf 文件名 UTF 8 30956 pdf 当它设置为附件时 浏览器将要求保存文件而不是打
  • 类的成员复制

    在学习 复制成员 概念时 书中给出了如下说法 此外 如果非静态成员是引用 const 或没有复制赋值的用户定义类型 则无法生成默认赋值 我不太明白这个声明到底想传达什么 或者说这个说法指的是哪一种场景 谢谢 该语句与编译器自动为您编写的类
  • 如何在 QTabWidget Qt 中展开选项卡

    我有一个QTabWidget像这个 但我想展开选项卡以 填充 整个小部件宽度 如下所示 我怎样才能做到这一点 我在用Qt 5 3 2 and Qt 创建者 3 2 1 Update 我尝试使用setExpanding功能 ui gt myT
  • std::forward_as_tuple 将参数传递给 2 个构造函数

    我想传递多个参数以便在函数内构造两个对象 以同样的方式std pair
  • C# 构建一个 webservice 方法,它接受 POST 方法,如 HttpWebRequest 方法

    我需要一个接受 POST 方法的 Web 服务 访问我的服务器正在使用 POST 方法 它向我发送了一个 xml 我应该用一些 xml 进行响应 另一方面 当我访问他时 我已经使用 HttpWebRequest 类进行了管理 并且工作正常
  • 如何在标准 WPF ListView 中启用 UI 虚拟化

    我正在使用 NET 4 5 VS2012 并且我有一个 ListView 看起来像这样
  • 每个租户的唯一用户名和电子邮件

    我正在使用以下代码编写多租户应用程序ASP NET Core 2 1 我想覆盖默认的与用户创建相关的验证机制 目前我无法创建多个具有相同的用户UserName My ApplicationUser模型有一个名为TenantID 我想要实现的
  • C# 中的 strstr() 等效项

    我有两个byte 我想找到第二个的第一次出现byte 在第一个byte 或其中的一个范围 我不想使用字符串来提高效率 翻译第一个byte to a string会效率低下 基本上我相信就是这样strstr 在 C 中做 最好的方法是什么 这
  • 我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

    我想在收到 SIGUSR1 后使用 ungetc 将 A 字符重新填充到标准输入中 想象一下我有充分的理由这样做 调用 foo 时 stdin 中的阻塞读取不会被收到信号时的 ungetc 调用中断 虽然我没想到它会按原样工作 但我想知道是
  • cout 和字符串连接

    我刚刚复习了我的 C 我尝试这样做 include
  • 了解使用 Windows 本机 WPF 客户端进行 ADFS 登录

    我已经阅读了大量有关 ADFS 与 NodeJS Angular 或其他前端 Web 框架集成以及一般流程如何工作的文献 并通过 Auth0 Angular 起始代码构建了概念证明 但我不明白如何这可以与本机 WPF Windows 应用程
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • C++ Streambuf 方法可以抛出异常吗?

    我正在尝试找到一种方法来获取读取或写入流的字符数 即使存在错误并且读 写结束时间较短 该方法也是可靠的 我正在做这样的事情 return stream rdbuf gt sputn buffer buffer size 但如果streamb
  • xsi:type 属性搞乱了 C# XML 反序列化

    我使用 XSD exe 根据 XML 架构 xsd 文件 自动生成 C 对象 我正在反序列化 OpenCover 输出 但其中一个部分类未正确生成 这是导致异常的行

随机推荐

  • 不允许任何人访问目录 .htaccess

    它可能很简单 但我找不到它 我想制作一个 htaccess 文件 这样任何人都无法进入该文件夹 除了服务器上的 php 之外 有谁知道代码行吗 谢谢 马蒂 You want Deny from all
  • 不同包中的类名相同

    同一类可以存在于多个包中吗 换句话说 我可以有Foo java上课于com test package1 and com test package2 Update 现在我从包 1 中复制了类并放入包 2 中 现在我正在创建该类的实例 我希望该
  • C# Regex.Split:删除空结果

    我正在开发一个应用程序 该应用程序导入数千行 其中每行的格式如下 9070183020 04 02 2011 107222 M S SUNNY MEDICOS GHAZIABAD 32 768 00 我正在使用以下Regex将行拆分为我需要
  • Apache2 Django NameError:名称“TypeError”未定义

    我试图通过 apache2 在 VPS 上运行 django 应用程序 但我在网站错误文件中收到以下内容 也是 400 错误请求 Exception ignored in
  • 可以使用 Python 标准库完成结构化日志记录吗?

    我最近读到了有关结构化日志记录的内容 here https stackify com what is structured logging and why developers need it 这个想法似乎不是通过将简单的字符串作为一行附加
  • Chromium 嵌入式框架:使用“ExecuteFunctionWithContext”时创建对象失败

    Overview 我在 Delphi 2009 上使用 chromium 嵌入式框架 cef 它是最新版本 Error 我可以用ExecuteFunctionWithContext成功执行 JavaScript 回调例程 我可以为其提供参数
  • 在 Glassfish 部署期间,WEB-INF/lib 中的 JAR 库未添加到类路径中

    尽管我已经使用 Java 几年了 但我还是 Glassfish 和 Java EE 的新手 我继承了一个停滞的项目 现在我需要重新开始开发 我正在尝试按原样部署 Web 应用程序 以查看哪些内容有效以及哪些内容需要注意 虽然实现各种功能的代
  • 如何防止(引导)固定顶部导航在移动设备上缩放

    在使用Bootstrap 3的固定顶部导航时 我注意到当用户在移动设备上使用原生缩放时 顶部导航也变得非常大 这会导致非常糟糕的用户体验 导航模糊了大部分内容并最终自行损坏 如以下示例所示 这个问题可以在网上看到http www explo
  • 如何暂停 android.speech.tts.TextToSpeech?

    我正在使用 Android TTS 播放文本 android speech tts TextToSpeech I use TextToSpeech speak说话和 stop停止 有没有办法也暂停文本 据我所知 TTS SDK 没有任何暂停
  • 如何仅修改react .map函数中的一个元素?

    我对反应有点陌生 并且对在这里做什么有点迷失 我正在从 firebase 加载数据并使用 map 函数渲染该对象的 props 以列出页面上的所有 评论 效果很好 我还想调用一个组件 该组件允许用户回复单个评论 即地图中的一个特定元素 但正
  • JPA:从属性创建 EntityManagerFactory

    我在 JAR 项目中使用 JPA 并使用 persistence xml 来设置我的 EntityManager 但由于 persistence xml 在构建后位于 JAR 内 因此用户随后更改设置非常复杂 因此 我正在寻找一种解决方案
  • C语言中数字之间插入空格

    我该如何获取像这样的数字123456并将其打印为1 2 3 4 5 6 最简单的方法 尽管不是最快的 可能是首先sprintf http linux die net man 3 sprintf将数字存入字符串缓冲区 然后循环遍历该缓冲区pr
  • 如何在 sbt 中有条件地调用任务?

    Say taskA是一项繁重的任务 只有在启用它并且taskAEnabled是对应的设置键 一个天真的方法是 val taskAConditional Def task taskAEnabled taskA map taskAEnabled
  • 为什么我的交叉表在 Excel 中被切断?

    我正在尝试使用 BIRT 创建 Excel 电子表格 该电子表格是将两个对象映射在一起的交叉表 行数和列数是根据 MySQL 数据库中的值动态变化的 目前我已经实现了 PDF 输出报告 现在 我正在尝试创建 Excel 报告的第二个版本 我
  • 使用 Rails 3.1.0 和 ubuntu 安装 Nokogiri 1.5.0 时出错

    这是在服务器上运行捆绑安装供应商 宝石时出现的错误 Installing nokogiri 1 5 0 with native extensions Gem Installer ExtensionBuildError ERROR Faile
  • 如何防止maven检查外部存储库?

    当我使用 Maven 构建时 我看到它检查所有类型的外部存储库中是否有只有我的本地构建应该生成的工件 我如何告诉它 com myorg 组只能在本地存储库中找到 基本上我想做 m2eclipse 对工作空间分辨率所做的事情 但在命令行上 I
  • 以编程方式更改导航标题

    我有一个带有标题的导航栏 当我双击文本对其进行重命名时 它实际上说它是一个导航项 所以可能就是这样 我正在尝试使用代码更改文本 例如 declare navigation bar as navagationbar here button s
  • 将多个 OSGi 包打包在同一个 jar 中

    我对 OSGi 平台非常陌生 拥有 OSGi 捆绑包B1依赖于另一个包B2 这很可能不是由容器提供的 我可以将两个包打包在同一个包中吗jar 如果是 该怎么做 如果jar已安装并且捆绑包已安装 是的 你可以这样做 有点 通常 OSGi 包是
  • 使用 AngularJS ui-grid $scope.saveRow 保存行数据

    我正在开发一个小型前端应用程序 它将在用户界面网格中显示各种产品运输数据 我有以下代码 HTML p row name works at row company p
  • 向 C# 添加“lazy”关键字时出现的问题

    我很想写这样的代码 class Zebra public lazy int StripeCount get return ExpensiveCountingMethodThatReallyOnlyNeedsToBeRunOnce 编辑 为什