【问题标题】:Java: Data structure for caching computation result?Java:缓存计算结果的数据结构?
【发布时间】:2010-12-05 20:41:03
【问题描述】:

我有一个昂贵的计算,我想缓存它的结果。有没有办法用两个键制作地图?我在想Map<(Thing1, Thing2), Integer>之类的东西。

然后我可以检查:

if (! cache.contains(thing1, thing2)) {
  return computeResult();
}
else {
  return cache.getValue(thing1, thing2);
}

伪代码。但是有些类似的东西。

【问题讨论】:

    标签: java caching map tuples computation


    【解决方案1】:

    您需要创建一个包含 Thing1 和 Thing2 的类,例如:

    class Things {
        public final Thing1 thing1;
        public final Thing2 thing2;
        public Things(Thing1 thing1, Thing2 thing2) {
          this.thing1 = thing1; 
          this.thing2 = thing2;
        }
        @Override
        public boolean equals(Object obj) { ... }
        @Override
        public int hashCode() { ... };
     }
    

    然后使用它:

    Things key = new Things(thing1, thing2);
    if (!cache.contains(key) {
        Integer result = computeResult();
        cache.put(key, result);
        return result;
    } else {
        return cache.getValue(key);
    }
    

    请注意,您必须实现 equals 和 hashcode 才能使此代码正常工作。如果您需要此代码是线程安全的,请查看 ConcurrentHashMap。

    【讨论】:

    • Eerie .. 我 刚刚 在五分钟前这样做了,然后来到 SO 并看到了这个问题......我推荐 hashCode 方法的这种实现(这是只是默认的 Eclipse 实现):return (31 + thing1.hashCode())*31 + thing2.hashCode();
    • @Kip:实际上,我建议使用来自 Apache Commons Lang 的 HashCodeBuilderEqualsBuilderCompareToBuilder。 :-)
    • 我花了不到 10 分钟来实现这个,现在我的程序在 25% 的时间内运行。哇。
    【解决方案2】:

    听起来你想要记忆。 Functional Java 的最新主干头有一个记忆产品类型 P1,它对计算结果进行了建模。

    你会这样使用它:

    P1<Thing> myThing = new P1<Thing>() {
      public Thing _1() {
        return expensiveComputation();
      }
    }.memo();
    

    第一次调用 _1() 将运行昂贵的计算并将其存储在备忘录中。之后,将返回备忘录。

    对于您的“两个键”,您需要一个简单的对类型。函数式 Java 也以类 P2&lt;A, B&gt; 的形式具有此功能。要记住这样的值,只需使用P1&lt;P2&lt;A, B&gt;&gt;

    您也可以使用Promise&lt;A&gt; 类代替记忆。这在库中已经有一段时间了,所以你只需要最新的二进制文件。您可以按如下方式使用它:

    Promise<Thing> myThing =
      parModule(sequentialStrategy).promise(new P1<Thing>() {
        public Thing _1() {
          return expensiveComputation();
        }
      });
    

    要获得结果,只需调用myThing.claim()Promise&lt;A&gt; 还提供了在结果上映射函数的方法即使结果尚未准备好

    您需要import static fj.control.parallel.ParModule.parModulefj.control.parallel.Strategy.sequentialStrategy。如果您希望计算在自己的线程中运行,请将sequentialStrategy 替换为Strategy 类提供的其他策略之一。

    【讨论】:

      【解决方案3】:

      如果你使用Google Collections,它的MapMaker 类有一个makeComputingMap 方法,它完全符合你的描述。作为免费奖励,它也是线程安全的(实现 ConcurrentMap)。

      至于双键的事情,你必须创建一个包含这两个键的类,并实现一个合适的equalshashCode 和(如果适用)compareTo 的实现。比较你想要的方式。

      【讨论】:

      • 我完全支持 Google 收藏,但我很难理解它是如何工作的。
      • 您基本上创建了一个Function 对象来调用您的computeResult 函数。当您从地图中获取适当的项目时,Google 对象将负责调用该函数并缓存其值。 :-)
      猜你喜欢
      • 1970-01-01
      • 2016-01-19
      • 2012-06-26
      • 2012-04-16
      • 1970-01-01
      • 1970-01-01
      • 2016-09-13
      • 2015-07-24
      • 2012-06-15
      相关资源
      最近更新 更多