osc*_*car 6 python django django-templates
一些分析显示模板渲染是罪魁祸首.(我正在尝试一个只有缓存查询的页面.)但是,模板非常简单.最复杂的部分是一个运行10次的嵌套循环,但是如果一切顺利,嵌套循环就不会运行,因为它被缓存了.(比如在我的测试中)
那是
{% for p in posts %}
--{{p.by.username}}
--{{p.text}}
{% cache 600 p p.timestamp %}
{% for img in p.images.all %}
--{{img.path}}
{% endfor %}
{% endcache %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
我在dev上得到了~80 req/s.此页面的服务器.(我发现我可以在生产部署中将该数字乘以3)为了进行比较,我得到1000req/s的简单模板只包含一个短的静态字符串.
这是一个已知问题吗?我该如何纠正/避免它?
小智 5
在开发模式下,django 做了很多事情来简化开发(例如:代码重新加载;如果使用模板,则为每个请求进行模板渲染;...)。
在生产模式下,优先部署 WSGI 服务器,然后再部署 django。这样的 wsgi 可能是gunicorn,uWSGI,...
典型的生产 Web 服务器的布局可能是:nginx -> Gunicorn -> django
一个简单的对比(django官方教程代码和一个非常简单的“Hello World!@time”模板):
{% block content %}
<p> Hello World! @ {{ now }}</p>
{% endblock %}
Run Code Online (Sandbox Code Playgroud)
python 管理.py runserver
ab -n1000 -c10 http://127.0.0.1:8000/polls/helloworld
Server Software: WSGIServer/0.2 # django
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /polls/helloworld
Document Length: 59 bytes
Concurrency Level: 10
Time taken for tests: 3.438 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 242000 bytes
HTML transferred: 59000 bytes
Requests per second: 290.87 [#/sec] (mean)
Time per request: 34.380 [ms] (mean)
Time per request: 3.438 [ms] (mean, across all concurrent requests)
Transfer rate: 68.74 [Kbytes/sec] received
Run Code Online (Sandbox Code Playgroud)
../bin/gunicorn -w4 mysite.wsgi # 有 4 个工人
ab -n1000 -c10 http://127.0.0.1:8000/polls/helloworld
Server Software: gunicorn/19.7.1 # gunicorn
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /polls/helloworld
Document Length: 59 bytes
Concurrency Level: 10
Time taken for tests: 0.618 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 248000 bytes
HTML transferred: 59000 bytes
Requests per second: 1619.10 [#/sec] (mean)
Time per request: 6.176 [ms] (mean)
Time per request: 0.618 [ms] (mean, across all concurrent requests)
Transfer rate: 392.13 [Kbytes/sec] received
Run Code Online (Sandbox Code Playgroud)
(显然我还没有足够的“业力”来发表评论,或者我会将其作为评论而不是答案发布)
您能详细说明一下“仅缓存查询”的含义吗?
除此之外,在我看来,您的问题可能是您在模板渲染期间频繁访问数据库。
{% for p in posts %}
--{{p.by.username}} {# 1 #}
--{{p.text}}
{% cache 600 p p.timestamp %}
{% for img in p.images.all %} {# 2 #}
--{{img.path}}
{% endfor %}
{% endcache %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
您向模板提供“帖子”;这是一个查询,您说过它有 100 个结果。
然后,对于帖子的每次迭代,您都将访问数据库以{# 1 #}获取 p.by,我认为它是 auth.User 的外键。
除此之外,由于缓存无效(第一次运行),您将再次访问数据库{# 2 #}以获取该帖子的图像列表。
因此,对于 100 个项目,初始运行时每个请求会访问数据库 201 次,图像循环的缓存已满,则访问数据库 101 次。
如果可能的话,尝试将select_lated与您的 posts 查询结合使用,将这些额外结果提取到一个查询中。类似的东西posts = Post.objects.select_related('by', 'images').filter(...)可能会起作用,尽管我知道select_related在反转外键和 m2m 字段方面存在限制(它可能不适用于图像,具体取决于您的模型结构)。