Java:缓存计算结果的数据结构?

时间:2009-10-12 02:18:42

标签: java caching map tuples computation

我有一个昂贵的计算,其结果我想缓存。有没有办法用两把钥匙制作地图?我在想Map<(Thing1, Thing2), Integer>

然后我可以检查:

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

伪代码。但是就这些问题而言。

3 个答案:

答案 0 :(得分:5)

您需要创建一个包含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。

答案 1 :(得分:3)

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

您可以这样使用它:

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

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

对于“两把钥匙”,你需要一个简单的配对类型。功能Java也以类P2<A, B>的形式提供此功能。要记住这样的值,只需使用P1<P2<A, B>>

您也可以使用Promise<A>类而不是memoisation。这已经在库中了一段时间,所以你只需要最新的二进制文件。您可以按如下方式使用它:

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

要获得结果,只需致电myThing.claim()即可。 Promise<A>还提供了在结果上映射函数的方法,即使结果尚未准备好

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

答案 2 :(得分:2)

如果您使用Google Collections,则其MapMaker类会使用makeComputingMap方法完全按照您的描述进行操作。作为免费奖励,它也是线程安全的(实现ConcurrentMap)。

对于双键事项,您必须创建一个包含两个键的类,并实现equalshashCode和(如果适用){{1}的合适实现以你想要的方式进行关键比较。