GAE Python优化:用于语言支持的Django过滤器

GAE Python优化:用于语言支持的Django过滤器,python,django,google-app-engine,filter,Python,Django,Google App Engine,Filter,我在我的webapp中使用了一个过滤器来支持lang。但当我把它发布到GAE时,它总是告诉我它的CPU使用率太高了 我想我找到了我的过滤器的问题,我使用的支持。我在模板中使用此选项: <h1>{{ "collection.header"|translate:lang }}</h1> 我刚接触Python,想看看它有什么问题。还是整个方法都是错误的 …弗雷德里克 关于我要做的事情,我只是想找到一个方法来处理语言支持。用户需要能够通过管理页面更新文本元素。到目前为止,所有

我在我的webapp中使用了一个过滤器来支持lang。但当我把它发布到GAE时,它总是告诉我它的CPU使用率太高了

我想我找到了我的过滤器的问题,我使用的支持。我在模板中使用此选项:

<h1>{{ "collection.header"|translate:lang }}</h1>
我刚接触Python,想看看它有什么问题。还是整个方法都是错误的

…弗雷德里克


关于我要做的事情,我只是想找到一个方法来处理语言支持。用户需要能够通过管理页面更新文本元素。到目前为止,所有文本元素都存储在db.model中。并使用过滤器根据语言获取正确的密钥

经过大量的测试,我仍然不能很好地工作。当发布时,我仍然会在日志中收到关于CPU使用量的错误消息。一个典型的页面大约有30-50个文本元素。根据日志,它使用大约1500ms(900ms API)来加载每个页面。我开始觉得这可能不是最好的方法

我已经尝试使用memcache和索引来解决CPU使用问题。这有点帮助。应该使用memcache并手动添加索引吗

这是我的过滤器的外观:

import re
from google.appengine.ext import webapp
from google.appengine.api import memcache

from util import dictionary

register = webapp.template.create_template_register()

def translate(key, lang):
    re = "no key for " + key

    data = memcache.get("dictionary" + lang)

    if data is None:
        data = dictionary.GetDictionaryKey(lang)
        memcache.add("dictionary" + lang, data, 60)

    if key in data:
        return data[key]
    else:   
        return "no key for " + key


register.filter(translate)
util.dictionary如下所示:

import re
from google.appengine.ext import webapp
from util import dictionary

register = webapp.template.create_template_register()

def translate(key, lang):
    d = dictionary.GetDictionaryKey(lang, key)
    if d == False:
        return "no key for " + key
    else: 
        return d.value

register.filter(translate)
from google.appengine.ext import db

class DictionaryEntries(db.Model):
    lang = db.StringProperty()
    dkey = db.StringProperty()
    value = db.TextProperty()
    params = db.StringProperty()

    @property
    def itemid(self):
        return self.key().id()

def GetDictionaryKey(lang):
    entries = DictionaryEntries.all().filter("lang = ", lang)
    if entries.count() > 0:
        langObj = {}
        for entry in entries:
            langObj[entry.dkey] = entry.value

        return langObj 
    else:
        return False
{% load i18n %}
<h1>{% trans "Header of my Collection" %}</h1>

您是否考虑过切换到标准的gettext方法?Gettext是一种广泛传播的国际化方法,非常好地嵌入到Python(和Django)世界中

一些链接:

然后,您的模板将如下所示:

import re
from google.appengine.ext import webapp
from util import dictionary

register = webapp.template.create_template_register()

def translate(key, lang):
    d = dictionary.GetDictionaryKey(lang, key)
    if d == False:
        return "no key for " + key
    else: 
        return d.value

register.filter(translate)
from google.appengine.ext import db

class DictionaryEntries(db.Model):
    lang = db.StringProperty()
    dkey = db.StringProperty()
    value = db.TextProperty()
    params = db.StringProperty()

    @property
    def itemid(self):
        return self.key().id()

def GetDictionaryKey(lang):
    entries = DictionaryEntries.all().filter("lang = ", lang)
    if entries.count() > 0:
        langObj = {}
        for entry in entries:
            langObj[entry.dkey] = entry.value

        return langObj 
    else:
        return False
{% load i18n %}
<h1>{% trans "Header of my Collection" %}</h1>
例如,用于生成法语(fr)消息


Gettext的性能相当好,所以我怀疑与在memcache中存储翻译表相比,使用这种方法的速度是否会明显减慢。更重要的是,它让您能够处理“真实”的消息,而不是抽象的字典键,至少在我的经验中,如果您必须阅读和理解代码(或者如果您必须查找和更改某条消息),这会更好。

您最初的问题是关于高cpu使用率,我认为答案很简单,对于GAE和BigTable(非关系型)等数据库,如果您有大量数据,则带有
entries.count()
的代码非常昂贵,而entrie中的
用于entry的代码也非常昂贵

我想你必须做几件事:

在您的
utils.py中

def GetDictionaryKey(lang, key):
    chache_key = 'dictionary_%s_%s' % (lang, key)
    data = memcache.get(cache_key)
    if not data:
         entry = DictionaryEntries.all().filter("lang = ", lang).filter("value =", key).get()
         if entry:
             data = memcache.add(cache_key, entry.value, 60)
         else:
             data = 'no result for %s' % key
    return data
在您的过滤器中:

 def translate(key, lang):
     return dictionary.GetDictionaryKey(lang, key)
这种方法更好,因为:

  • 您不需要进行昂贵的查询
    count
  • 您尊重MVC模式,因为过滤器是模板(模式中的视图)的一部分,而方法
    GetDictionaryKey
    是控件的一部分
此外,如果您正在使用django,我建议您缓动您的cache_密钥:

from django.template.defaultfilters import slugify
def GetDictionaryKey(lang, key):
    chache_key = 'dictionary_%s_%s' % (slugify(lang), slugify(key))
    data = memcache.get(cache_key)
    if not data:
         entry = DictionaryEntries.all().filter("lang = ", lang).filter("value =", key).get()
         if entry:
             data = memcache.add(cache_key, entry.value, 60)
         else:
             data = 'no result for %s' % key
    return data

我把所有与DictionaryRight有关的类和方法都放在这里,如果瓶颈确实在这里,那么它可能在dictionary.GetDictionaryKey()中。如果看不到它,很难判断它有什么问题:)您可以通过为每种语言创建新的reponseHandler来摆脱它。为您做更多工作,但每个请求的性能更好。GAE喜欢每个请求的响应时间非常低,以支持扩展。不总是可能的,而且开发人员经常需要做更多的工作。所以不要花时间在上面,除非你期待很快会有巨大的流量。我以前看过。也许这是一个更好的方法。我唯一搞不清楚的是,如何根据用户在托管@google时添加到数据库中的内容生成语言文件。有没有基于db.Model生成这些文件的方法?对不起,我今天可能有点慢,但是“基于用户添加到数据库中的内容”是什么意思?你想翻译用户生成的任意字符串吗?是的。我有一个设置页面,管理员用户可以在其中添加/编辑/删除字典中的条目。字典有两个名为“lang”和“dkey”的字符串属性,我使用它们来确定要获取的条目。它的工作原理有点像CMS的轻版本。然后它会变得非常讨厌PO文件。我会绞尽脑汁更新答案,如果我找到一个好方法(也就是说,你不必自己解析.po文件…)的话。如果您有任何想法,我们将不胜感激+从我这里得到1。我还没有测试过它,但这是合理的,这将导致性能的提高@弗雷德里克:如果是这样,你应该接受这个答案。我的gettext方法对于开发人员可以控制的文本很好,但我还没有找到一种使用Django的gettext支持进行用户输入翻译的好方法。@diegueus9:Tanks。我一到家就去试试。我去度假一周了。我似乎无法更改接受状态。我会给stackoverflow团队发电子邮件,看看他们是否能改变它。@diegueus9:工作非常愉快!再次感谢。有一件事。当添加到memcache时,您需要进行一次访问。因为memcache.add如果添加成功与否,只会返回True或False。@fredrik我很高兴为您工作,是的,我有这个错误,但我编写所有代码时没有测试;)非常好的工作就在你的头顶上!仍在等待stackoverflow团队的响应。希望他们能改变它,这样你就能得到赏金点数了。