【问题标题】:Caching Scala Case Class Instances缓存 Scala 案例类实例
【发布时间】:2016-11-14 06:06:29
【问题描述】:

假设我们有以下案例类:

abstract sealed class Tree
case class Leaf(i: Int) extends Tree
case class Node(left: Tree, right: Tree) extends Tree

每次调用案例类构造函数时,都会在内存中创建一个新对象。例如,在下面的代码中:

val a = Leaf(0)
val b = Leaf(0) 

a 和 b 指向内存中不同的对象:

a == b // true
a eq b // false

我想重写案例类的“apply”方法,让它们返回一个缓存对象,以防它已经存在,这样,在上面的最小示例中,“a eq b”将返回 true。

我在 Stackoverflow 中找到了这两个相关的答案:

我计划以结合上面链接的两种方法的方式实现我的覆盖“应用”方法和缓存。但我想知道是否有其他方法可以考虑。如果您知道,可以在这里分享您的解决方案吗?

缓存案例类的实例似乎是减少内存消耗的一件非常有用且自然的事情。然而,我计划实施的解决方案(基于上面链接的两个答案)似乎相​​当复杂,需要大量样板代码,这会损害案例类的优雅和简洁性。有谁知道未来版本的 Scala 语言是否允许我们通过编写如下简单的代码来实现案例类实例缓存:

abstract sealed class Tree
cached case class Leaf(i: Int) extends Tree
cached case class Node(left: Tree, right: Tree) extends Tree

??

【问题讨论】:

  • 只是一个随机问题,您是否将这种“缓存”视为任何其他语言的核心功能?至少我还没有遇到过。
  • 我也没有。这让我想知道是否有原因。 @Alexey Romanov 下面的回答指出了一些有趣的原因。

标签: scala caching case-class


【解决方案1】:

缓存案例类的实例似乎是减少内存消耗的一件非常有用且自然的事情。

请注意,这甚至不是远程自动改进,很大程度上取决于案例类的使用模式(不仅是您的,而是使用您的库的任何人):

    1234563他们自己的密钥,直接或间接地”)。
  1. 如果键是原语(如Leaf),则需要在查找之前将它们装箱,这通常已经是构造函数调用。

  2. 在地图中查找比普通的构造函数调用慢得多。

  3. 转义分析通常会确保对象并未实际构造,同时确保您的程序它们那样工作。当然,缓存会确保对象确实逃逸。

但是忽略所有这些,您可以编写一个宏注释,它允许您 @cached case class Leaf(i: Int) extends Tree 并生成您想要的代码(或至少 @cachedcase class;我不确定您是否能够覆盖 apply除此以外)。由于上述原因,我只是不希望它很快成为语言的一部分。

【讨论】:

  • 这些都是好点,尽管其中一些不适用于我的特定使用模式。你能详细说明你的第4点吗?我怎么知道什么时候不会构造一个新对象?我在哪里可以了解更多信息?
  • 您能提供一个带有@cachedcase 宏注释的最小示例吗?
  • 基本解释见docs.oracle.com/javase/7/docs/technotes/guides/vm/…。这个想法是,如果一个对象仅在方法期间使用并且不“转义”,则可以通过用局部变量替换所有字段来消除它。但是检查是否消除了任何特定的分配绝非易事(而且无论如何都需要 JIT 启动,因此尝试一次是行不通的)。参见例如psy-lob-saw.blogspot.se/2014/12/….
  • 对于@cachedcase 示例,您是指使用还是实现?用法为@cachedcase class Leaf(i: Int) extends Tree。实施将需要我目前没有的时间,尤其是要做好。
  • 谢谢。我的意思是实施,而不是使用。不过不用担心。
猜你喜欢
  • 2020-07-29
  • 1970-01-01
  • 1970-01-01
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
  • 2014-04-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多