用于共享大型不可变对象的工厂/缓存策略

我的问题很像以前的postOptimal HashSet Initialization(Scala | Java) ,我想使用HashSet加速(目前我正在使用Set ),但HashSet没有表现出它的(恒定时间)优势。

对于提到的解决方案:

您可以通过实习来最小化等于的成本。 这意味着您通过工厂方法获取类的新对象,该方法检查所请求的新对象是否已存在,如果是,则返回对现有对象的引用。 如果断言此类型的每个对象都是以这种方式构造的,那么您就知道每个不同对象只有一个实例,而equals等同于对象标识,这是一个廉价的引用比较(Scala中的eq)。

但是,我不太清楚检查的有效方法是什么

请求的新对象是否已存在

对于大对象(例如,带有hashmap参数的case类的对象,一些其他对象结构……等)

通过比较每个复杂的领域不会给出太多的性能优势,不是吗? 或者如果是,还有其他方法吗?

另外,我也很困惑如何制作

equals等同于对象标识,这是一个廉价的参考比较(Scala中的eq)。

在代码中。

我认为,上面提到的intening技术基本上是一个对象缓存。 因此,我参考了Java中小型不可变对象的后缓存策略中提到的技术? 。 但是,我仍然没有看到大型物体的有效方式。

为方便起见,我引用了post中的缓存技术(用Java), ///表示我的想法和问题:

 private static final int N_POINTS = 10191; private static final Point[] POINTS = new Point[N_POINTS]; public static Point of(int x, int y, int z) { int h = hash(x,y,z); /// I can use hash code of each complicated field to construct the value int index = (h & 0x7fffffff) % N_POINTS; Point p = POINTS[index]; if (p != null && px == x && py == y && pz == z) /// Not working for large objects? return p; return POINTS[index] = new Point(x,y,z); } 

总而言之,为大型对象实现高效缓存策略的最佳实践是什么,以便我可以利用Scala中的HashSet

谢谢,

实习的目标是使用引用相等来实现equals方法: this eq that (或者this == that Java中的this == that )。 很明显,与比较某些字段集的更传统的 equals相比,此实现具有最佳的运行时特性。

只有当对象的某些字段集合确定每个“唯一对象”中只有一个实例时,此比较才有效。

只有在实际操作的前期成本可以被HashMap驱动的(可能很多)调用equals的最小化成本完全抵消时, 实习才有效。

正如您所指出的,此实习可能需要一个可能代价高昂的缓存机制:运行时开销(执行检查)和内存开销(缓存大小)。

  • 缓存最直接的方法是使用HashMap ,传统的equalshashCode应该是懒惰的; 缓存它的结果,因此不需要重新计算。 可能需要考虑线程问题。

  • 实现这样的高速缓存的一种方法是使用trie ,可能在每个节点处使用散列表实现,并且其中每个“级别”对应于对象中的字段(第一级 – 字段1,第二级,字段2等。 …)用于“用于建立唯一性的字段集”。

还有其他可行的方法来实现这样的缓存。 请原谅我避免进一步讨论此类问题,并允许我提出避免处理问题的方法。

选项1:没有缓存

声明: 通过使用快速哈希(并在内部缓存), equals的“传统”实现,以及具有足够最小大小的HashMapHashSet ,您可能会获得足够有效的结果

理想情况下,哈希表中的冲突很少,并且对equals的调用次数最少。

选项2:将多个字段映射到一个唯一的String

[此方法假定“唯一定义对象的字段”是不可变的。 如果不是这样,可以进行适当的调整以补偿。]

构建和缓存private unique: String与唯一对象实例对应的private unique: String 。 例如,对于某些简单对象,以下内容可能是唯一的:

用逗号分隔的“用于建立唯一性的字段集”的字符串值的串联。

了解对象/字段特征将有助于确定如何创建这样一个唯一字符串。

有了这样的值,我们就可以避免单独的实习/缓存机制,并通过在这个unique字符串方面实现equalshashCode来保留很多好处:

 def equals(thatObj: Any) = thatObj match { case that : MyType => unique.equals(that.unique) case _ => false } def hashCode() = unique.hashCode 

选项2的替代方案:

[编辑:RüdigerKlaehn提供了这个链接,提供了令人信服的证据,以避免String.intern() ]

使用String.intern并调整equals以利用它:

 private val unique = buildUnique().intern def equals(thatObj: Any) = thatObj match { case that : MyType => unique.eq(that.unique) // In Java: unique == that.unique case _ => false }