【问题标题】:How do I implement caching in an immutable way?如何以不可变的方式实现缓存?
【发布时间】:2014-03-03 01:35:26
【问题描述】:

我已经阅读了 heardimmutability 的很多好东西,所以我决定在我的一个爱好项目中尝试一下。我将我的所有字段声明为只读,并创建了所有通常会改变对象以返回新的修改版本的方法。

在我遇到这样一种情况之前,它工作得很好,一个方法应该通过外部协议返回有关对象的某些信息而不修改它,但同时可以通过修改内部结构来优化。特别是,tree path compressionunion find algorithm 中会发生这种情况。

当用户调用int find(int n) 时,对象在外人看来是未经修改的。它在概念上表示相同的实体,但它的内部字段已发生变化以优化运行时间。

如何以不可变的方式实现这一点?

【问题讨论】:

  • 我想说,如果你以线程安全的方式进行突变,并且它不会被外人检测到,那么它可以被认为是不可变的。
  • @Joe 但这样我必须自己维护线程安全。据我所知,不变性的美妙之处在于,我只需指定 readonly 关键字就可以将其留给语言。
  • 但你说过你想改变它。如果您不以线程安全的方式执行此操作,您将失去不可变类型的好处之一(线程安全)。
  • 我可以想象一个解决方案,你的类有一个惰性求值的属性(可能使用Lazy<T>)来实现你的优化。
  • Chris Okasaki 有一本书《函数式数据结构》,也许对你有帮助(如果你还没有读过的话)。

标签: c# immutability


【解决方案1】:

简短回答:您必须自己确保线程安全。

字段上的readonly 关键字可确保在构造包含该字段的对象后无法修改该字段。 因此,您可以对该字段进行的唯一写入包含在构造函数中(或字段初始化中),并且在构造对象之前无法通过方法调用进行读取,因此readonly 的线程安全。

如果你想实现缓存,你打破了只发生一次写入的假设(因为“缓存写入”可以而且将会在你读取期间发生),因此在糟糕的情况下可能会出现线程问题(认为你正在阅读来自文件的行,两个线程可以使用相同的参数调用 find 方法,但读取两个不同的行,因此得到不同的结果)。 你想要实现的是observational immutability。这个related question about memoization 可以帮助你得到一个优雅的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 2011-07-15
    • 1970-01-01
    相关资源
    最近更新 更多