【问题标题】:Purely functional equivalent of weakhashmap?纯功能等效于弱哈希图?
【发布时间】:2011-01-17 13:53:29
【问题描述】:

Java's weak hash map 这样的弱哈希表使用弱引用来跟踪垃圾收集器对无法访问的键的集合,并从集合中删除与该键的绑定。弱哈希表通常用于实现从图中的一个顶点或边到另一个顶点或边的间接寻址,因为它们允许垃圾收集器收集图中无法到达的部分。

这种数据结构是否存在纯粹的功能等价物?如果没有,如何创建?

这似乎是一个有趣的挑战。内部实现不可能是纯粹的,因为它必须收集(即变异)数据结构以删除无法访问的部分,但我相信它可以为用户提供一个纯粹的界面,用户永远无法观察到杂质,因为它们只影响数据的一部分根据定义,用户无法再访问的结构。

【问题讨论】:

    标签: data-structures weak-references purely-functional


    【解决方案1】:

    这是一个有趣的概念。 “纯功能”设置中的一个主要并发症是对象身份通常在“纯功能”意义上是不可观察的。即,如果我复制一个对象或创建一个新的相同对象,在 Java 中,预计克隆不是原始对象。但在功能设置中,期望新的在语义上与旧的相同,即使垃圾收集器会以不同的方式处理它。

    因此,如果我们允许对象标识成为语义的一部分,那将是合理的,否则可能不会。在后一种情况下,即使可以找到一个 hack(我想到了一个,如下所述),你很可能会让语言实现到处与你争吵,因为它会做各种各样的事情来利用这个事实该对象身份不应该是可观察的。

    我想到的一个“技巧”是使用唯一构造值作为键,以便在大多数情况下,值相等与引用相等一致。例如,我在 Haskell 中有一个我个人使用的库,其界面中有以下内容:

    data Uniq s
    getUniq :: IO (Uniq RealWorld)
    instance Eq (Uniq s)
    instance Ord (Uniq s)
    

    像您描述的哈希映射可能主要使用这些作为键,但即使在这里我也能想到一种可能会破坏的方法:假设用户将键存储在某个数据结构的严格字段中,使用编译器的启用“unbox-strict-fields”优化。如果 'Uniq' 只是机器整数的新类型包装器,则可能不再有 GC 可以指向并说“这是关键”的任何对象;因此,当用户打开钥匙使用它时,地图可能已经忘记了它。 (编辑:这个特定的例子显然可以解决;使 Uniq 的实现成为不能像那样拆箱的东西;关键是它很棘手,因为编译器试图在很多方面提供帮助,我们可能不会期待)

    TL;DR:我不会说它不能完成,但我怀疑在许多情况下,“优化”会被弱散列映射实现破坏或破坏,除非对象标识是一流的可观察的状态。

    【讨论】:

      【解决方案2】:

      从用户的角度来看,纯粹的功能性数据结构是无法改变的。所以,如果我从哈希映射中获得一个键,等待,然后再次获得相同的键,我必须获得相同的值。我可以抓住钥匙,所以它们不会消失。

      唯一可行的方法是,如果 API 为我提供了下一代,并且在释放对容器过去版本的所有引用之前不收集值。预计数据结构的用户会定期要求新一代发布弱持有的价值。

      编辑(基于评论):我理解您想要的行为,但您无法使用释放对象的地图通过此测试:

      FunctionalWeakHashMap map = new FunctionalWeakHashMap();
      
      { // make scope to make o have no references
         Object o = new SomeObject();
         map["key"] = o;
      }  // at this point I lose all references to o, and the reference is weak
      
      // wait as much time as you think it takes for that weak reference to collect, 
      // force it, etc
      
      Assert.isNotNull(map["key"]); // this must be true or map is not persistent
      

      我建议这个测试可以通过

      FunctionalWeakHashMap map = new FunctionalWeakHashMap();
      
      { // make scope to make o have no references
         Object o = new SomeObject();
         map["key"] = o;
      }  // at this point I lose all references to o, and the reference is weak in the map
      
      // wait as much time as you think it takes for that weak reference to collect, 
      // force it, etc
      
      map = map.nextGen();
      
      Assert.isNull(map["key"]); 
      

      【讨论】:

      • 不完全。弱哈希映射的全部意义在于 GC 会自动释放无法访问的子图,而程序员不必定期要求它这样做。
      • 我特别想说的是,这不能与持久数据结构一起使用,并提供了一种调和这两种行为的方法。你的问题是你认为我达不到,但我可以。我没有对对象的引用(当然),但我有一个键。
      • 您对行为的解释是错误的。当 key 变得无法访问时,弱哈希映射中的绑定将被删除。您在反例中保留了密钥,因此无法收集该密钥的绑定,因此不存在此类问题。 o 的可达性无关紧要。我看不出为什么这不能与持久数据结构一起工作,因为它只会影响无法访问的值的语义,根据定义,这些值是不可观察的。
      • 但是可以重新创建键对象——来自文档:“此类将与不基于对象标识的 equals 方法的键对象完美配合,例如 String 实例。使用此类可重新创建的键对象,但是,自动删除键已被丢弃的 WeakHashMap 条目可能会令人困惑。”
      • 如果可以重新创建密钥,可以。但如果他们不能呢?那是天生不纯洁的吗?这个要求会阻止持久性吗?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多