Java: структура данных для кэширования результатов вычислений? - PullRequest
2 голосов
/ 12 октября 2009

У меня дорогие вычисления, результат которых я бы хотел кешировать. Есть ли способ сделать карту с двумя ключами? Я думаю о чем-то вроде Map<(Thing1, Thing2), Integer>.

Тогда я мог бы проверить:

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

псевдокод. Но что-то в этом роде.

Ответы [ 3 ]

5 голосов
/ 12 октября 2009

Вам необходимо создать класс, содержащий 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.

3 голосов
/ 12 октября 2009

Звучит так, будто ты хочешь запоминания. Последний заголовок магистрали Функциональная 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> вместо запоминания. Это было в библиотеке некоторое время, так что вам просто нужен последний бинарный файл. Вы бы использовали это следующим образом:

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

Чтобы получить результат, просто позвоните myThing.claim(). Promise<A> также предоставляет методы для отображения функций на результат , даже если результат еще не готов .

Вам нужно import static fj.control.parallel.ParModule.parModule и fj.control.parallel.Strategy.sequentialStrategy. Если вы хотите, чтобы вычисления выполнялись в собственном потоке, замените sequentialStrategy одной из других стратегий, предоставляемых классом Strategy.

2 голосов
/ 12 октября 2009

Если вы используете Google Collections , его класс MapMaker имеет метод makeComputingMap, который делает именно то, что вы описали. В качестве бесплатного бонуса он также ориентирован на многопоточность (реализует ConcurrentMap).

Что касается вещи с двумя ключами, вам нужно создать класс, который содержит два ключа, и реализовать подходящую реализацию equals, hashCode и (если применимо) compareTo, которая выполняет ключ Сравнение так, как вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...