2010-10-23 6 views
5

Je déplace une application Web Google App Engine en dehors du "cloud" vers un framework Web standard (webpy) et j'aimerais savoir comment implémenter une fonctionnalité memcache disponible sur Gae.Homemade tiny memcache

Dans mon application, j'utilise simplement ce cache pour stocker un tas de données extraites d'une API distante toutes les X heures; en d'autres termes je ne souligne pas trop ce cache.

J'ai naïvement mis en œuvre quelque chose comme ceci:

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 

Une utilisation typique serait:

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 

Comment pourrais-je améliorer?
Ai-je besoin de le rendre résistant aux threads?

+1

La plupart des "frameworks web standard" supportent la connexion à un backend cache ... Pourquoi ne pas implémenter un wrapper qui essaye le backend GAE, et s'il n'est pas disponible, revient à 'memcached' (ou à l'API Django Cache, si vous utilisez Django). Avez-vous accès à une instance memcache "hors du cloud"? –

+0

Non, memcached n'est pas une option car elle n'est pas supportée par mon fournisseur. En outre, le backend GAE n'est pas une option aussi ... pourquoi ai-je besoin d'un aller-retour si long pour quelque chose qui doit être rapide? – systempuntoout

Répondre

2

Il me semble que votre cache peut augmenter de façon inefficace car il conservera les entrées rarement utilisées. Parce que, il semble que les entrées dans votre cache ne sont pas supprimées sauf si une opération get est demandée pour une clé spécifique.

Si vous voulez améliorer votre cache, je rajouterais les deux caractéristiques simples suivantes:

  1. Lorsqu'un élément est demandé je redémarrer seconds à la valeur initiale. Donc, pour garder les éléments que votre système utilise souvent.
  2. Je voudrais implémenter dans un thread séparé un mécanisme pour parcourir le cache et supprimer les entrées qui sont trop vieilles.

vous pouvez également obtenir quelques idées de ce Fixed size cache

Edité

Je viens de découvrir cette recette, il est super cool. Fondamentalement, vous pouvez emballer avec des décorateurs de fonction la logique que vous voulez mettre en cache. Quelque chose comme:

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

Ces LRU and LFU cache decorator décorateurs mettra en œuvre pour vous la logique de cache. Le plus récemment utilisé (LRU) ou le moins fréquemment utilisé (voir Cache_algorithms pour référence)

+0

jolis points, merci – systempuntoout

+0

@systempuntoout vient d'être édité avec une autre solution basée sur les décorateurs de fonctions. –

+0

En fait, j'ai déjà un cache LRU sur mon projet. Ce dont j'ai vraiment besoin, c'est d'un cache pour les objets qui expire avec le temps. – systempuntoout

0

Dans mon application, j'utilise simplement ce cache pour stocker un tas de données extraites d'une API distante toutes les X heures; en d'autres termes je ne souligne pas trop ce cache.

...

Comment pourrais-je améliorer?

Si votre code fonctionne pour vous, pourquoi s'embêter?

Cependant, comme vous avez explicitement demandé des commentaires, j'essaie d'ajouter mes idées quand même. Pour moi, il semble que vous pourriez utiliser un stockage traditionnel comme des fichiers ou une base de données pour stocker les données car il est seulement actualisé périodiquement. Dans de nombreux cas, il suffit d'un pré-traitement (potentiellement coûteux), vous pouvez donc vous concentrer sur le travail une fois et simplement stocker les données dans un formulaire afin que l'accès/la livraison au client soit rapide.

Avantages:

  • simples
  • aucun problème avec de nombreux processus (par exemple FastCGI)
  • réduite d'impression pied mémoire

Ai-je besoin de le rendre thread-safe?

Cela dépend vraiment de votre modèle d'utilisation. Cependant, à partir de votre API, je suppose que ce n'est pas vraiment nécessaire car vous calculez une valeur deux fois (pire des cas).