Django 1.11 中表单渲染性能不佳

Posted

技术标签:

【中文标题】Django 1.11 中表单渲染性能不佳【英文标题】:Poor Performance for Form Rendering In Django 1.11 【发布时间】:2019-05-05 03:35:35 【问题描述】:

My site 有一个带有高级搜索小部件的导航栏(在搜索字段旁边),它呈现在每个页面上。对于每个请求,context_processor 创建表单,以便它可以在导航栏中的该页面上可用。这个表格有大约十几个选项,总共有几百个选项。其中大部分选项是针对货币和国家/地区选择的,还有大约 80 个其他选项。 “商店”还有一个更大的列表,但它是通过 AJAX 加载的,所以这里不应该是一个因素。

在 Django 1.8 上性能很好,但在升级到 1.11 (Pyton 2.7.15) 后,我注意到在 NewRelic 中,我最频繁的请求现在使用了超过 500 毫秒:

渲染/django/forms/widgets/select_option.html 渲染/django/forms/widgets/select.html 渲染/django/forms/widgets/attrs.html

这似乎与 1.11 对 Template-based Widget Rendering (docs) 的更改有关,但是我能找到的唯一讨论相关问题的页面是关于我没有在生产中运行的 Django Toolbar。

我正在并且已经在使用缓存模板加载器(现在是默认设置),但是我不知道这是否有帮助。我无法轻松缓存此表单,因为正如您在代码中看到的那样,我根据请求设置了许多默认值。

为什么我的表单会因这种变化而受到如此严重的影响?消除两个较大的选择会有所帮助,但肯定数百个选项不应该花这么长时间来呈现,所以在我看来,存在一个潜在的问题,即数量只是在加剧。

这里是完整表单和 html 代码的链接。 (稍后我们确定问题时,我将在问题中包含 sn-ps,以供将来的读者使用。

Search Form Search HTML Live Site Discussion on Mailing List

更新

在这篇文章之后,我禁用了这些选择中最大的一个,并且一瘸一拐地过了一年。本周我实施了一个解决方法,这样我就可以重新启用这些选项而无需支付巨大的成本。我现在缓存表单的模板片段,将选定的表单搜索选项传递给前端,并使用 javascript 进行设置。

【问题讨论】:

【参考方案1】:

如果您确实将小部件呈现作为性能瓶颈隔离,您可以使用不同的模板为此制作自己的小部件。

class OptimizedSelectWidget(forms.Select):
    template_name = "widget_templates/optimized_select.html"

class MyForm(forms.Form):
    field = forms.ChoiceField(choices=XXX, widget=OptimizedSelectWidget)

OptimizedSelectWidget 的模板越简单,渲染的速度就越快。以下是支持选择小部件全部功能的选择小部件的通用(即最复杂)模板。我通过使用 Django 2.2 下拉模板并内联所有子模板以获取选项。

<select name=" widget.name "% include "django/forms/widgets/attrs.html" %>% for group_name, group_choices, group_index in widget.optgroups %% if group_name %
  <optgroup label=" group_name ">% endif %% for option in group_choices %
  <option value=" option.value|stringformat:'s' " % for name, value in option.attrs.items %% if value is not False %  name % if value is not True %=" value|stringformat:'s' "% endif %% endif %% endfor %> option.label </option>% endfor %% if group_name %
  </optgroup>% endif %% endfor %
</select>

我已经在下拉渲染是一个性能问题的页面上尝试过这个,并且确实得到了一些加速,但它在 20% 的范围内,而不是 5 倍的范围内。我的理论是模板缓存已经做了很多,所以模板本身的开销并没有那么高。也就是说,这是在 Django 2.2 上进行的,它可能在 1.11 上引入了一些实质性的性能改进。

我最终解决的这个问题(让我获得 5 倍加速的解决方案)是使用 Angular 将渲染下拉选项移动到浏览器。 Angular 或 React 等前端框架只能用于渲染页面的一小部分;您不必重做整个前端就可以做到这一点。

【讨论】:

根据我的更新,鉴于我在过去 11 个月中直到上周在您发布此内容之前才处理此问题,因此您的回答时机具有讽刺意味。 20% 可能还不够,但我非常感谢您抽出时间分享这些想法,并希望它们对某人有用。 @JohnLehmann 听起来我们得出了相同的结论:使用 JavaScript 渲染选项。【参考方案2】:

你有相同请求的过去数据,升级前有什么吗?如果您在入门计划中,也许您只有 7 天的数据:单击 time-pick 并将其设置为该日期,然后您可以将过去的信息与当前的信息进行比较以确定瓶颈。

【讨论】:

谢谢,但我已经知道减速在哪里,我在上面详细说明了。此时的问题更像是一个 Django 问题,为什么模板变得如此缓慢以及如何解决它。

以上是关于Django 1.11 中表单渲染性能不佳的主要内容,如果未能解决你的问题,请参考以下文章

Django ORM 与 Oracle 的性能不佳

在 Android 中使用带有 OpenGL ES 的 VBO 性能不佳

SQL Server 查询性能不佳

H264解码性能不佳

在 Amazon EC2 微型实例上从 Apache 切换后 uWSGI/nginx/Django 性能不佳

BIG IP F5 WCF NetTCpBinding 性能不佳