一个 web 应用开发者遇到了一个与语言支持相关的过滤问题。当他将其发布到 GAE 时,它不断提示 CPU 使用率过高。他认为问题出自他用于支持的筛选器。他在模板中使用了这种方式:
<h1>{{ "collection.header"|translate:lang }}</h1>
其筛选器代码如下:
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)
他对于 Python 不太熟悉,无法发现其中的问题所在,并且不确定这样的方法是否是完全错误的。
他希望寻找一种方法来处理语言支持。用户需要能够通过管理页面更新文本元素。目前,所有文本元素都存储在一个数据库模型中,并使用一个筛选器根据语言来获取正确的键。
经过大量的测试,他仍然无法让它足够好地工作。在发布后,他仍然在日志中收到有关 CPU 使用率过高的错误消息。一个典型的页面大约有 30-50 个文本元素,而根据日志,每次页面加载大约使用 1500ms(API 为 900ms)。他开始认为这可能不是最好的方法。
他还尝试同时使用 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
代码如下:
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
2、解决方案
第一个答案提供了一个简洁的解决方案,指出问题在于对 entries.count()
和 for entry in entries
的昂贵查询。他建议使用 Memcache 来缓存查询结果,并对查询进行轻量化。
from utils import dictionary
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)
第二个答案则建议使用标准的 gettext
方法,它是 Python 和 Django 中广泛应用的一种国际化方法。这个方法使用 .po
文件来存储翻译,并在运行时动态加载。
{% load i18n %}
<h1>{% trans "Header of my Collection" %}</h1>
这两个答案都提供了有效的解决方案,可以帮助开发者优化 GAE Python 应用程序的语言支持,并降低 CPU 使用率。