my ideal cache using guava

Off and on przez ostatnie kilka tygodni próbowałem znaleźć moją idealną implementację pamięci podręcznej przy użyciu Guava MapMaker . Zobacz moje poprzednie dwa pytania tutaj i tutaj aby śledzić mój proces myślowy.

Biorąc to, czego się nauczyłem, moja następna próba porzuci miękkie wartości na rzecz maximumSize i expireAfterAccess:

ConcurrentMap<String, MyObject> cache = new MapMaker()
        .maximumSize(MAXIMUM_SIZE)
        .expireAfterAccess(MINUTES_TO_EXPIRY, TimeUnit.MINUTES)
        .makeComputingMap(loadFunction);

Gdzie

Function<String, MyObject> loadFunction = new Function<String, MyObject>() {
   @Override
   public MyObject apply(String uidKey) {
      return getFromDataBase(uidKey);
   }
};

Jednakże, jedynym problemem, z którym wciąż się borykam, jest to, że ta implementacja będzie eksmitować obiekty, nawet jeśli są one silnie osiągalne, gdy ich czas się skończy. Może to spowodować, że wiele obiektów z tym samym UID będzie krążyć w środowisku, czego nie chcę (wierzę, że to, co próbuję osiągnąć, jest znane jako kanonicalizacja).

Z tego co wiem, jedyną odpowiedzią jest posiadanie dodatkowej mapy, która działa jako interner, którą mogę sprawdzić, czy obiekt danych jest jeszcze w pamięci:

ConcurrentMap<String, MyObject> interner = new MapMaker()
        .weakValues()
        .makeMap();

I funkcja load będzie zmieniony:

Function<String, MyObject> loadFunction = new Function<String, MyObject>() {
   @Override
   public MyObject apply(String uidKey) {
      MyObject dataObject = interner.get(uidKey);
      if (dataObject == null) {
         dataObject = getFromDataBase(uidKey);
         interner.put(uidKey, dataObject);
      }
      return dataObject;
   }
};

Jednak używanie dwóch map zamiast jednej dla pamięci podręcznej wydaje się nieefektywne. Czy istnieje bardziej wyrafinowany sposób podejścia do tego? Ogólnie rzecz biorąc, czy robię to we właściwy sposób, Czy powinienem przemyśleć swoją strategię buforowania?

Author: Community, 2011-07-21

2 answers

To, czy dwie mapy są wydajne, zależy całkowicie od tego, jak drogie jest getFromDatabase() i jak duże są Twoje obiekty. Nie wydaje mi się, aby robić coś takiego poza wszelkimi rozsądnymi granicami.

Jeśli chodzi o implementację, wygląda na to, że możesz prawdopodobnie warstwować mapy w nieco inny sposób, aby uzyskać pożądane zachowanie i nadal mieć dobre właściwości współbieżności.

  1. Utwórz swoją pierwszą mapę ze słabymi wartościami i włącz funkcję obliczeniową getFromDatabase () ta mapa.
  2. druga mapa to wygasająca, również obliczająca, ale ta funkcja pochodzi właśnie z pierwszej mapy.

Wykonaj cały dostęp przez drugą mapę.

Innymi słowy, wygasająca Mapa działa, aby przypiąć ostatnio używany podzbiór obiektów do pamięci, podczas gdy słaba Mapa odniesienia jest rzeczywistą pamięcią podręczną.

-dg

 8
Author: Darren Gilroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-25 06:39:54

Nie rozumiem tu całego obrazu, ale dwie rzeczy.

  1. Biorąc pod uwagę to stwierdzenie: "Ta implementacja będzie eksmitować obiekty, nawet jeśli są one silnie osiągalne, gdy ich czas się skończy. Może to spowodować, że wiele obiektów o tym samym identyfikatorze UID będzie krążyć w środowisku, czego nie chcę."--wygląda na to, że po prostu musisz użyć weakkeys () i nie używać eksmisji opartej na czasie ani rozmiarze.

  2. Albo jeśli chcesz wciągnąć w to" internera", użyj prawdziwego Interners.newWeakInterner.

 0
Author: Kevin Bourrillion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-25 19:40:37