gpt4 book ai didi

c# - 向 C# 添加 `lazy` 关键字的问题

转载 作者:IT王子 更新时间:2023-10-29 03:59:47 24 4
gpt4 key购买 nike

我很想写这样的代码:

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 中的代码。块,然后只会从中返回值。

我的问题:
  • 将这种关键字添加到库中会涉及哪些成本?
  • 这在什么情况下会出现问题?
  • 你觉得这有用吗?

  • 我不是要开始讨伐这个库的下一个版本,但我很好奇像这样的功能应该经过什么样的考虑。

    最佳答案

    I am curious what kind of considerations a feature such as this should have to go through.



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

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

    和我的新博客:

    http://ericlippert.com

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

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

    What costs would be involved with adding this kind of keyword to the library?



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

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

    What situations would this be problematic in?



    我可以想到许多因素会导致我推迟该功能。

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

    其次,更重要的是,它在语言中体现了一种特殊的惰性。懒惰不止一种,我们可能会选择错误。

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

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

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

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

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

    这会为该功能增加更多成本,该成本由没有利用它的人平均承担(因为他们正在编写单线程程序)。

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

    第三,该功能似乎很弱。为什么懒惰只适用于属性(property)?似乎这可以通过类型系统普遍应用:
    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

    如果有一个更一般的特征是它的自然延伸,我们尽量不做小而弱的特征。但现在我们谈论的是非常严重的设计和实现成本。

    Would you find this useful?



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

    关于c# - 向 C# 添加 `lazy` 关键字的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5965968/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com