Voici mon problème:Accélération des modèles dans GAE-Py en agrégeant appels RPC
class City(Model):
name = StringProperty()
class Author(Model):
name = StringProperty()
city = ReferenceProperty(City)
class Post(Model):
author = ReferenceProperty(Author)
content = StringProperty()
Le code n'a pas d'importance ... ce modèle son django:
{% for post in posts %}
<div>{{post.content}}</div>
<div>by {{post.author.name}} from {{post.author.city.name}}</div>
{% endfor %}
Maintenant, supposons que je obtenir les 100 premiers messages en utilisant Post.all().fetch(limit=100)
, et passer cette liste au modèle - que se passe-t-il?
200 plus banque de données obtient - 100 pour obtenir chaque auteur, 100 pour obtenir la ville de chaque auteur.
Ceci est parfaitement compréhensible, en fait, puisque le post a seulement une référence à l'auteur, et l'auteur a seulement une référence à la ville. L'accesseur __get__
sur les objets post.author
et author.city
permet de récupérer et de récupérer les données de manière transparente (voir la question this).
Quelques façons de contourner ce sont
- Utilisez
Post.author.get_value_for_datastore(post)
pour récupérer les clés de l'auteur (voir le lien ci-dessus), puis faire un lot apprendre à les obtenir tous - le problème est ici que nous devons re- Construire un objet de données de modèle ... quelque chose qui a besoin de code supplémentaire et de maintenance pour chaque modèle et gestionnaire. - Ecrivez un accesseur, disons
cached_author
, qui vérifie d'abord memcache pour l'auteur et le renvoie - le problème ici est que post.cached_author va être appelé 100 fois, ce qui pourrait probablement signifier 100 appels memcache. - Conservez une clé statique dans la mappe d'objet (et actualisez-la peut-être une fois toutes les cinq minutes) si les données ne doivent pas forcément être à jour. L'accesseur
cached_author
peut alors simplement se référer à cette carte.
Toutes ces idées nécessitent un code et une maintenance supplémentaires, et elles ne sont pas très transparentes. Et si nous pouvions faire
@prefetch
def render_template(path, data)
template.render(path, data)
Il s'avère que nous pouvons ... hooks et Guido's instrumentation module à la fois prouver. Si la méthode @prefetch
enveloppe un rendu de modèle en capturant quelles clés sont demandées, nous pouvons (au moins à un niveau de profondeur) capturer quelles clés sont demandées, renvoyer des objets simulés, et faire un batch sur eux. Cela pourrait être répété pour tous les niveaux de profondeur, jusqu'à ce qu'aucune nouvelle clé ne soit demandée. Le rendu final pourrait intercepter les get et retourner les objets d'une carte.
Cela changerait un total de 200 pénètre dans , de manière transparente et sans code supplémentaire. Sans oublier de réduire considérablement le besoin de memcache et d'aider dans les situations où memcache ne peut pas être utilisé.
Problème, je ne sais pas comment le faire (encore). Avant que je commence à essayer, quelqu'un d'autre a-t-il fait cela? Ou est-ce que quelqu'un veut aider? Ou voyez-vous une faille massive dans le plan?
Quelque chose que j'omis de ma réponse ... vous pouvez ou ne peut pas se rendre compte que les appels RPC une re * extrêmement * lent par rapport à votre code Python, et il compte contre votre quota. Le magasin de données de l'IIRC récupère par clé environ 100ms, donc 200 fetch prendrait 20 secondes. Vous êtes en train de faire 400 fetchs (un de poste à auteur, un de l'auteur à la ville), ce qui va expirer votre page. – JasonSmith
Précisément ... ma page actuelle ne montrera probablement que 10 messages, et j'enregistre 40 appels. Prend un peu plus d'une seconde, appelle ce nombre dans les années 100 pourrait facilement délai. –
Aussi, hooray pour un utilisateur dans le fuseau horaire> = GMT + 5 (je suppose)! Enfin, je peux répondre avant que tous les Occidentaux le fassent! : p – JasonSmith