Django-使用templatetags呈现许多模板非常慢

Django-使用templatetags呈现许多模板非常慢,django,optimization,django-templates,Django,Optimization,Django Templates,比如说,我有一个带有照片库的页面。每个缩略图都有照片、国家、作者等。我使用模板标签(加载指定的模板)呈现这些项目/小部件-这是因为DRY(我在页面的不同位置分别使用这些项目/小部件) 而且速度非常慢 我使用django调试工具栏执行了一些评测: SQL Queries: default 84.81 ms (147 queries) 但是: 等待的时间太长了 经过一番分析,原来罪魁祸首是模板引擎 当我想显示150张照片时,600个相关项目/小部件通过模板呈现。这意味着600次I/O操作甚至更多。

比如说,我有一个带有照片库的页面。每个缩略图都有照片、国家、作者等。我使用模板标签(加载指定的模板)呈现这些项目/小部件-这是因为DRY(我在页面的不同位置分别使用这些项目/小部件)

而且速度非常慢

我使用django调试工具栏执行了一些评测:

SQL Queries: default 84.81 ms (147 queries)
但是:

等待的时间太长了

经过一番分析,原来罪魁祸首是模板引擎

当我想显示150张照片时,600个相关项目/小部件通过模板呈现。这意味着600次I/O操作甚至更多。将这些小部件移动到主模板可以解决问题,但不会保持干燥

所以我的问题是如何避免这种行为?是干燥缓慢还是不干燥快速? 我宁愿干爽快速…

您可能想试试,
django.template.loaders.cached.Loader
——它肯定会减少所需的IO量


编辑以添加您需要小心,不要仅仅因为大部分时间都花在模板呈现阶段,就认为查询计数不是问题所在。不要忘记QuerySet是惰性的,除非您在视图中专门对它们进行切片或迭代,否则只有在加载模板时才会对它们进行计算。我想说,通过良好地使用
select\u-related
和其他技术来减少查询计数应该是非常有帮助的。

我假设,因为您使用的是调试工具栏,所以您在开发中获得了这些数字。然而,正因为如此,这些都不是“真实”的数字

内置的Django服务器有利于开发,但它有许多缺点,使得它比真正的Web服务器慢得多。首先,它是单线程的,所以这意味着没有并行请求。这也意味着IO操作是离散的。其次,它的任务不仅仅是为Django提供请求,还包括静态资源


长话短说,如果你想真实地分析你的站点的页面加载时间,你需要在本地安装一个真正的Web服务器。基本上就像在生产环境中一样进行设置。我愿意打赌请求时间会好得多。

这可能不适用于这个特定的问题,但在某些情况下,它帮助我在查询中使用
选择相关的
。可能不是这样,但它可能会降低您的查询计数。

经过几个小时的分析和搜索

感谢您的帮助,但在这种情况下,我认为目前为止最好的解决方案是使用:

我试过了,获得了70-80%的速度性能

{% load cache %}
{% cache 3600 mywidget_id %}
    .. rendered mywidget is cached ..
{% endcache %}

花在查询上的时间相对较少。 但是ORM需要更多的时间来生成这些查询并将结果解析到模型实例中

{% for photo in photos|annotate_comment_count %}
   ...
{% endfor %}

def annotate_comment_count(photo_list):
    counts = dict(Comment.objects.filter(photo__in=photo_list).values('photo') \
                                 .annotate(count=models.Count('id')))
    for photo in photo_list:
        photo.comments_count = counts[photo.pk]
    return photo_list
因此,尽管有大量的查询,但由于ORM速度慢(在您的情况下,这可能需要一秒钟),您的应用程序仍然受到CPU的限制。因此,无论如何,您必须减少查询的数量

查询很可能是在模板标记内部进行的。因此,您必须在几次查询中获得所需的数据,并在照片实例上进行设置

{% for photo in photos|annotate_comment_count %}
   ...
{% endfor %}

def annotate_comment_count(photo_list):
    counts = dict(Comment.objects.filter(photo__in=photo_list).values('photo') \
                                 .annotate(count=models.Count('id')))
    for photo in photo_list:
        photo.comments_count = counts[photo.pk]
    return photo_list

因此,在templatetag中,您不必查询单个照片的评论计数,但在
comments\u count
属性中已经有了此信息。您在一次查询中就实现了这一点。

我也有同样的问题,可能是出于同样的原因。我优化了自定义模板标记的性能。数据库请求的数量从640个下降到2个,结果数据库时间不到20ms。然而,我的页面变慢了!7秒->10秒。唉。我尝试了一个缓存的模板加载程序,但没有效果


我放弃了,禁用了django调试工具栏,之后响应时间下降到1.2秒,难以置信!!在我的例子中,巨大的响应时间只是由调试工具栏引起的!可以找到一个相关的问题。我没有深入讨论这个工具栏问题,因为我计划无论如何使用模板片段缓存来缓存模板标记。在开发过程中,我每15分钟有10秒的响应时间,我可以接受。无论如何,希望这有帮助。

谢谢。它将其降低到5054.582毫秒,即约11%的增益。但是,渲染仍然需要5秒。这里还可以做什么?它在第二页加载时的性能如何?相同的-5秒是最小值。这令人惊讶。缓存的模板加载器将解析后的模板存储在进程内存中,这意味着I/O可能不是瓶颈。您是否尝试过使用调试工具栏查看发生了什么?缓存的模板加载器工作正常,因为模板中的更改看起来不是实时的。需要冲洗。将所有内容移动到主模板会使加载该页面的速度非常快(1-1.5秒)。这就是为什么我认为它是I/O。但正如我在问题中所说的,它会干涸。你能提供templatetag代码吗?花在查询上的时间相对较少。但是ORM需要更多的时间来生成这些查询并将结果解析为模型实例。请注意,由于Django 1.4,runserver是线程化的,因此它可以处理并行请求。与SELECT_相关的查询不是一组84ms的查询。这是关于模板的。