为什么Django模板渲染字典如此缓慢?

8
当我使用django 1.4的默认模板系统渲染一个中等复杂的字典(4级深度,约2K数据点)时,模板渲染步骤需要超过2800毫秒。如果我直接从Python生成HTML,则只需要大约80毫秒。即使使用另一个模板库(如jinja2),也可以在不到300毫秒的时间内呈现相同的数据(实际上,几乎完全相同的模板语法 - 因为jinja2几乎是一种可替换的工具)。有趣的是,您甚至不必在模板中实际呈现字典就能导致django模板系统的性能问题...您只需将其作为可用变量传递给模板即可。我的一个朋友建议这可能意味着系统正在"...进行防御性复制或(更愚蠢的是)理解[这将]由于运行构造函数而花费时间"。是否有人知道为什么django的默认模板系统需要如此长时间才能呈现字典?* 我将在下面添加请求的详细信息 *。我正在调试模式下运行,并将DebugToolbarMiddleware设置为我的中间件类之一。我的settings.py文件包括:
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
    'django.core.context_processors.request',
)

和……

# rendering like this
return render(
    request,
    template_name='ltm/search_results.html',
    context_instance=RequestContext(request, {
        'menus': menus,
        'results': result_dict
    })
)

4
为什么不使用cProfile runserver而让我们猜测呢?我们没有你的数据。你有任何高级的上下文处理器吗? - Pavel Anossov
你能提供一个使用虚拟数据的可运行示例吗? - Steven Rumbalski
虽然不是回答你的问题,但值得一看:Django的Jinja2适配器 - Joseph Victor Zammit
@PavelAnossov... +1 简短的回答?因为这是我第一次听说cProfile :) 我会解决这个问题并发布更新。可能需要一些时间,因为我正在紧迫期限内工作,并且能够使用jinja2避开此问题并继续处理其他问题。只是好奇是否有更有经验的人知道这是一个已知问题。但你说得很对,这很可能是与我的设置有关的特定问题。 - codemonkey
Jinja2的性能比Django模板要好得多。 - Paulo Scardine
1个回答

2
如果您能提供模板代码,以便更好地了解我们正在处理的模板处理类型,那将非常好。
首先,遍历字典内容的方式可能存在差异。dict.items()返回一个元组列表,这会消耗额外的内存并需要时间来初始化,但是如果使用dict.iteritems(),访问键和值比通过生成器更快。
当您传递以点号.为前缀的变量名时,例如foo.bar.baz,在Django模板中会出现一些开销,执行所谓的variable lookup,尝试确定您是通过键访问字典项,还是通过索引访问对象的属性或列表项。我没有使用Jinja2,因此与变量查找有关的问题可能完全不相关,但如果两者之间存在差异,则值得考虑。
在任一情况下,由于您正在处理一个相当大的字典,如果您可以重新组织它在视图中的结构,以简化后续在模板中访问数据的方式,那么可能会有所帮助。

谢谢您发布这个问题。我很遗憾我没有时间更新我的问题。当我有时间时,我计划尝试使用一个非常简单的示例来复现这种行为。在我的测试中,我尝试了items()和iteritems()。我非常担心我在模板中引用字典的方式会导致问题。这就是为什么我尝试用“hello world”模板替换它的原因。重要的是要理解,这几乎没有影响渲染时间。因此,我相信迟缓与实际渲染无关。 - codemonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接