python - 通过聚合 RPC 调用来加速 GAE-Py 中的模板

标签 python google-app-engine django-templates

这是我的问题:

class City(Model):
  name = StringProperty()

class Author(Model):
  name = StringProperty()
  city = ReferenceProperty(City)

class Post(Model):
  author = ReferenceProperty(Author)
  content = StringProperty()

代码并不重要......它是这个 django 模板:

{% for post in posts %}
<div>{{post.content}}</div>
<div>by {{post.author.name}} from {{post.author.city.name}}</div>
{% endfor %}

现在假设我使用 Post.all().fetch(limit=100) 获取前 100 篇帖子,并将此列表传递给模板 - 会发生什么?

这使得200多个数据存储区获得 - 100 获得每个作者,100 获得每个作者所在的城市。

实际上,这是完全可以理解的,因为该帖子仅引用了作者,而作者仅引用了城市。 post.authorauthor.city 对象上的 __get__ 访问器透明地执行获取并拉回数据(请参阅 this 问题) .

解决这个问题的一些方法是

  1. 使用 Post.author.get_value_for_datastore(post) 收集作者 key (请参阅上面的链接),然后执行批量获取以获取所有 key - 这里的问题是我们需要重新构建模板数据对象...每个模型和处理程序都需要额外的代码和维护。
  2. 编写一个访问器,例如 cached_author,首先检查作者的 memcache 并返回 - 这里的问题是 post.cached_author 将被调用 100 次,这可能意味着 100 个 memcache来电。
  3. 如果数据不必是最新的,则保留对象映射的静态 key (并可能每五分钟刷新一次)。然后 cached_author 访问器就可以引用这个映射。

所有这些想法都需要额外的代码和维护,而且它们不是很透明。如果我们可以做什么

@prefetch
def render_template(path, data)    
  template.render(path, data)

事实证明我们可以... hooksGuido's instrumentation module两者都证明了这一点。如果 @prefetch 方法通过捕获请求的键来包装模板渲染,我们可以(至少到一个深度)捕获正在请求的键,返回模拟对象,并对它们进行批量获取。可以对所有深度级别重复此操作,直到没有请求新 key 为止。最终渲染可以拦截获取并从 map 返回对象。

这会将总共 200 次访问更改为 3,透明且无需任何额外代码。更不用说大大减少了对 memcache 的需求,并在无法使用 memcache 的情况下提供帮助。

问题是我还不知道该怎么做。在我开始尝试之前,有其他人这样做过吗?或者有人愿意帮忙吗?或者您认为该计划存在巨大缺陷?

最佳答案

我也遇到过类似的情况。我没有使用 ReferenceProperty,而是建立了父/子关系,但基础知识是相同的。我当前的解决方案尚未完善,但至少对于报告和具有 200-1,000 个实体的事物来说足够高效,每个实体都有几个需要提取的后续子实体。

您可以手动批量搜索数据,并根据需要进行设置。

# Given the posts, fetches all the data the template will need
# with just 2 key-only loads from the datastore.
posts = get_the_posts()

author_keys = [Post.author.get_value_for_datastore(x) for x in posts]
authors = db.get(author_keys)

city_keys = [Author.city.get_value_for_datastore(x) for x in authors]
cities = db.get(city_keys)

for post, author, city in zip(posts, authors, cities):
  post.author = author
  author.city = city

现在,当您渲染模板时,不会执行任何其他查询或获取。它的边缘很粗糙,但如果没有我刚才描述的这种模式,我就无法生活。

此外,您还可以考虑验证您的实体是否都为 None,因为如果 key 错误,db.get() 将返回 None。不过,这只是基本的数据验证。同样,如果出现超时等情况,需要重试db.get()。

(最后,我认为 memcache 不会作为主要解决方案。也许作为辅助层来加速数据存储调用,但如果 memcache 为空,您需要很好地工作。此外,Memcache 本身有几个配额,例如memcache 调用和传输的总数据量。过度使用 memcache 是杀死应用程序的好方法。)

关于python - 通过聚合 RPC 调用来加速 GAE-Py 中的模板,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2076470/

相关文章:

java - JDO - 嵌入类中的 HashMap

django - 如何向 Django 模板中的自定义模板过滤器添加多个参数?

django - 如何从 Django 模板中的页面迭代 cms 插件实例?

django - 如何通过 TemplateView.as_view 重定向到 .html 文件

python - 如何矢量化 Pandas 函数,该函数计算属于一个组且介于两个日期之间的行?

python - python asyncio 协程可以有不带等待的代码路径吗?

python - 如何存储其中包含 `"` 的字符串?

python - 警告 : the scripts . ....... 安装在不在路径上的某个地方

java - 如何从 java.sql.SQLException : Concurrent Modification 重试/恢复

google-app-engine - Google App Engine 与网络托管计划相比如何?