2010-10-23 10 views
5

Ich bin eine Google App Engine-Webanwendung außerhalb der "Cloud" zu einem Standard-Web-Framework (webpy) und ich würde gerne wissen, wie ein Feature auf Gae zu implementieren.Hausgemachte winzige Memcache

In meiner App verwende ich nur diesen Cache, um eine Reihe von Daten aus einer Remote-API alle X Stunden gespeichert zu speichern; Mit anderen Worten, ich betone diesen Cache nicht zu sehr.

Ich habe naiv so etwas wie dies umgesetzt:

class TinyCache(): 
    class _Container(): 
     def __init__(self, value, seconds): 
      self.value = value 
      self.cache_age = datetime.now() 
      self.cache_time = timedelta(seconds = seconds) 
     def is_stale(self): 
      return self.cache_age + self.cache_time < datetime.now() 

    def __init__(self): 
     self.dict_cache={} 

    def add(self, key, value, seconds = 7200): 
     self.dict_cache[key] = self._Container(value, seconds) 

    def get(self, key): 
     if key in self.dict_cache: 
      if self.dict_cache[key].is_stale(): 
       del self.dict_cache[key] 
       return None 
      else: 
       return self.dict_cache[key].value 
     else: 
      return None 

Eine typische Anwendung wäre:

data = tinycache.get("remote_api_data") 
if data is not None: 
    return data 
else: 
    data = self.api_call() 
    tinycache.add("remote_api_data", data, 7200) 
    return data 

Wie könnte ich es verbessern?
Muss ich es Thread-sicher machen?

+1

Die meisten "Standard-Web-Frameworks" unterstützen das Anhängen an ein Cache-Backend ... Warum nicht einen Wrapper implementieren, der das GAE-Backend versucht, und falls nicht verfügbar, fällt es zurück auf 'memcached' (oder die Django Cache API, wenn Sie gerade Django benutzen). Haben Sie Zugriff auf eine Memcache-Instanz "out of the cloud"? –

+0

Nein, memcached ist keine Option, da es nicht von meinem Provider unterstützt wird. Auch GAE Backend ist keine Option zu ... Warum brauche ich so eine längliche Rundreise für etwas, das schnell sein muss? – systempuntoout

Antwort

2

Es scheint mir, dass Ihr Cache ineffizient wachsen kann, da Einträge selten verwendet werden. Weil, es scheint, dass die Einträge in Ihrem Cache nicht entfernt werden, wenn eine get Operation für einen bestimmten Schlüssel angefordert wird.

Wenn Sie Ihren Cache verbessern würde ich die folgenden zwei einfachen Funktionen hinzuzufügen:

  1. Wenn ein Element angefordert wird, ich seconds auf den Anfangswert neu starten würde. So halten Sie die Elemente, die Ihr System oft verwendet.
  2. Ich würde in einem separaten Thread einen Mechanismus implementieren, um den Cache zu durchlaufen und Einträge zu löschen, die zu alt sind.

Sie auch einige Ideen aus diesem Fixed size cache bekommen

Edited

Ich habe gerade dieses Rezept, es ist super-cool. Im Grunde genommen können Sie mit Funktionsdekoratoren die Logik füllen, die Sie zwischenspeichern möchten. Etwas wie:

@lru_cache(maxsize=20) 
def my_expensive_function(x, y): 
    # my expensive logic here 
    return result 

Diese LRU and LFU cache decorator Dekorateure wird für Sie die Cache-Logik implementieren. Least Recently Used (LRU) oder Least Frequently Used (LFU) (siehe Cache_algorithms als Referenz hier)

+0

schöne Punkte, danke – systempuntoout

+0

@systempuntoout gerade mit einer anderen Lösung basierend auf Funktion Dekorateuren bearbeitet. –

+0

Eigentlich habe ich bereits einen LRU Cache auf meinem Projekt. Was ich wirklich brauche, ist ein Cache für Items, die mit der Zeit ablaufen. – systempuntoout

0

In meiner App verwende ich nur diesen Cache, um eine Reihe von Daten zu speichern, die alle X Stunden von einer Remote-API abgerufen werden; Mit anderen Worten, ich betone diesen Cache nicht zu sehr.

...

Wie könnte ich es verbessern?

Wenn Ihr Code für Sie funktioniert, warum?

Wie auch immer Sie explizit nach Kommentaren gefragt haben, versuche ich trotzdem meine Ideen hinzuzufügen. Für mich klingt es so, als könnten Sie einen herkömmlichen Speicher wie Dateien oder eine Datenbank verwenden, um die Daten zu speichern, da sie nur periodisch aktualisiert werden. In vielen Fällen benötigt man nur eine (möglicherweise teure) Vorverarbeitung, so dass Sie sich möglicherweise darauf konzentrieren können, die Arbeit einmal auszuführen und die Daten nur in einem Formular zu speichern, damit der Zugriff auf den Client schnell erfolgt.

Vorteile:

  • einfach
  • keine Probleme mit mehreren Prozessen (zum Beispiel FastCGI)
  • reduzierten Speicherplatzbedarf

Muss ich es Thread-sicher machen?

Das hängt wirklich von Ihrem Verwendungsmuster ab. Aber von Ihrer API ist das nicht wirklich notwendig, da Sie einen Wert zweimal berechnen (worst case).