性能和优化

本文档提供了一些技术和工具的概述,这些技术和工具可以帮助您更快速地运行您的Django代码,并且使用更少的系统资源。

引言¶ T0>

一般来说,首先要关注的是编写作品的代码,其逻辑功能按照要求产生预期的输出。 然而,有时候,这样还不足以使代码像那样高效地工作。

在这种情况下,需要什么东西 - 实际上,通常是一些东西的集合 - 在没有影响其行为的情况下或只是最小程度地改善代码的性能。

一般方法

你在为?优化什么?

有一个清楚的想法是很重要的,你的意思是“表现”。 它不只有一个指标。

提高速度可能是程序最明显的目标,但是有时可能会寻求其他性能改进,如内存消耗较低或对数据库或网络的要求较少。

一个领域的改进往往会带来另一个领域的改进,但并非总是如此。有时甚至可以牺牲另一个。 例如,程序速度的提高可能会导致它使用更多的内存。 更糟糕的是,这可能是自我挫败的 - 如果速度的提高如此消耗记忆力以至于系统开始耗尽内存,那么将会造成更多的伤害。

还有其他的权衡需要记住。 你自己的时间是一个宝贵的资源,比CPU时间更珍贵。 一些改进可能太难以值得实施,或者可能影响代码的可移植性或可维护性。 并不是所有的性能改进都是值得的。

所以,你需要知道你的目标是什么样的性能改进,而且你也需要知道你有一个很好的理由去瞄准这个方向 - 为此你需要:

性能基准测试

只是猜测或假设代码中的效率低下是不好的。

Django工具

django-debug-toolbar is a very handy tool that provides insights into what your code is doing and how much time it spends doing it. 特别是它可以显示你的页面正在产生的所有SQL查询,以及每个页面所花费的时间。

第三方面板也可用于工具栏,可以(例如)报告缓存性能和模板渲染时间。

第三方服务

有一些免费的服务,将从远程HTTP客户端的角度分析和报告您的网站的页面的性能,实际上模拟一个实际的用户的经验。

这些不能报告你的代码的内部,但可以提供一个有用的见解,您的网站的整体性能,包括不能从Django环境中充分测量的方面。 例子包括:

还有一些付费服务可以执行类似的分析,其中包括一些支持Django的付费服务,可以与您的代码库集成以更全面地分析其性能。

从一开始就做好准备

一些优化工作涉及解决性能缺陷,但是一些工作可以简单地建立在你将要做的事情上,作为在开始考虑提高性能之前应该采用的良好实践的一部分。

在这方面,Python是一个优秀的语言,因为看起来优雅和感觉正确的解决方案通常是最好的。 与大多数技能一样,学习“看起来正确”的做法需要练习,但最有用的指导方针之一是:

工作在适当的级别

Django提供了很多不同的方法来处理事情,但仅仅因为可以用某种方式来做某件事情并不意味着它是最合适的方式。 例如,你可能会发现你可以计算同样的东西 - 一个集合中的项目数量,也许 - 在一个QuerySet,Python或模板中。

但是,在低层而不是高层做这项工作几乎总是会更快。 在更高层次上,系统必须通过多层抽象和多层机器来处理对象。

也就是说,数据库通常可以比Python更快地完成任务,这比模板语言能做得更快:

# QuerySet operation on the database
# fast, because that's what databases are good at
my_bicycles.count()

# counting Python objects
# slower, because it requires a database query anyway, and processing
# of the Python objects
len(my_bicycles)

# Django template filter
# slower still, because it will have to count them in Python anyway,
# and because of template language overheads
{{ my_bicycles|length }}

一般来说,最合适的工作水平是编码舒适的最底层。

注意

上面的例子仅仅是说明性的。

Firstly, in a real-life case you need to consider what is happening before and after your count to work out what’s an optimal way of doing it in that particular context. The database optimization documents describes a case where counting in the template would be better.

其次,还有其他选择需要考虑:在现实生活中,{{ my_bicycles.count }} t0 >,它直接从模板中调用QuerySet count()方法,可能是最合适的选择。

缓存¶ T0>

通常,计算一个值是很昂贵的(即资源消耗和速度慢),所以在将值保存到快速访问的缓存中可能会有巨大的好处,可以在下一次需要的时候做好准备。

这是一个足够重要和强大的技术,Django包括一个全面的缓存框架,以及其他小块的缓存功能。

The caching framework

通过保存动态内容,Django的caching framework为性能提升提供了非常重要的机会,因此不需要为每个请求计算它。

为了方便起见,Django提供了不同级别的缓存粒度:您可以缓存特定视图的输出,或缓存难以生成的片断,甚至整个站点。

实现缓存不应被视为改善代码执行效率不佳的替代方法,因为它写得不好。 这是产生性能良好的代码的最后一步,而不是一个捷径。

cached_property

不得不多次调用一个类实例的方法。 如果这个功能很贵,那么这样做可能是浪费的。

使用cached_property修饰器保存属性返回的值;下次在该实例上调用函数时,它将返回保存的值而不是重新计算它。 请注意,这只适用于以self作为唯一参数的方法,并将方法更改为属性。

某些Django组件也有自己的缓存功能;这些将在下面与这些组件相关的章节中讨论。

理解懒惰

Laziness is a strategy complementary to caching. 缓存通过保存结果避免重新计算;懒惰延迟计算,直到实际需要。

懒惰使我们可以在实例化之前,甚至在实例化之前引用它们。 这有很多用途。

例如,可以在甚至知道目标语言之前使用lazy translation,因为直到翻译的字符串实际上是必需的,例如在渲染的模板中才发生。

懒惰也是一种努力避免工作的努力。 也就是说,懒惰的一个方面在做完之前什么也没有做,毕竟这可能不是必须的。 因此,懒惰可能会带来性能上的影响,有关的工作越昂贵,通过懒惰就越有可能获得。

Python为懒惰评估提供了许多工具,特别是通过generatorgenerator expression结构。 在Python中懒惰的阅读是值得的,以发现在代码中使用惰性模式的机会。

懒惰在Django

Django本身就很懒惰。 一个很好的例子可以在QuerySets的评估中找到。 QuerySets are lazy Thus a QuerySet can be created, passed around and combined with other QuerySets, without actually incurring any trips to the database to fetch the items it describes. 传递的是QuerySet对象,而不是最终将从数据库中获取的项目集合。

On the other hand, certain operations will force the evaluation of a QuerySet. 避免过早地评估一个QuerySet可以节省昂贵而不必要的数据库访问。

Django还提供了一个keep_lazy()修饰器。 这允许一个懒惰的参数被调用的函数本身懒惰地行为,只有当它需要被评估。 因此,懒惰的争论 - 可能是一个昂贵的争论 - 在严格要求之前不会被要求评估。

数据库¶ T0>

数据库优化

Django的数据库层提供了多种方法来帮助开发人员从数据库中获得最佳性能。 database optimization documentation汇集了相关文档的链接,并添加了各种提示,概述了尝试优化数据库使用情况时要采取的步骤。

HTTP性能

中间件¶ T0>

Django提供了几个有用的middleware,可以帮助您优化网站的性能。 他们包括:

ConditionalGetMiddleware

添加对现代浏览器的支持,以基于ETagLast-Modified标头有条件地获取响应。 它也计算并设置一个ETag,如果需要的话。

GZipMiddleware

压缩所有现代浏览器的响应,节省带宽和传输时间。 请注意,GZipMiddleware目前被认为是一种安全风险,容易受到TLS / SSL提供的保护无效的攻击。 有关更多信息,请参阅GZipMiddleware中的警告。

会话¶ T0>

使用缓存的会话

Using cached sessions可以通过消除像数据库那样从较慢的存储源加载会话数据并将经常使用的会话数据存储在内存中来提高性能。

静态文件

根据定义,静态文件不是动态的,是优化收益的极佳目标。

CachedStaticFilesStorage

通过利用网页浏览器的缓存功能,您可以在初始下载后完全消除指定文件的网络点击率。

CachedStaticFilesStorage appends a content-dependent tag to the filenames of static files to make it safe for browsers to cache them long-term without missing future changes - when a file changes, so will the tag, so browsers will reload the asset automatically.

“缩小” ¶ T0>

几个第三方的Django工具和包提供了“缩小”HTML,CSS和JavaScript的能力。 它们删除不必要的空白,换行符和注释,并缩短变量名称,从而减少网站发布文档的大小。

模板性能

注意:

  • using {% block %} is faster than using {% include %}
  • 由许多小块组装而成的大量碎片化模板可能会影响性能

缓存的模板加载器

Enabling the cached template loader often improves performance drastically, as it avoids compiling each template every time it needs to be rendered.

使用不同版本的可用软件

有时候可能需要检查一下你使用的软件是否有不同的,性能更好的版本。

这些技术针对的是更高级的用户,他们希望推动已经非常优化的Django站点的性能边界。

然而,它们并不是解决性能问题的神奇解决方案,它们不可能给那些尚未以正确的方式做更基本的事情的网站带来更好的边际收益。

注意

It’s worth repeating: reaching for alternatives to software you’re already using is never the first answer to performance problems. 当达到这个优化级别时,您需要一个正式的基准测试解决方案。

较新的往往是 - 但并不总是 - 更好

新版本维护良好的软件效率不高,但维护人员无法预测所有可能的使用情况,因此在知道新版本可能表现更好的情况下,不要简单地假设他们一直会。

Django本身也是如此。 连续发行的版本已经在整个系统中提供了许多改进,但是您仍然应该检查应用程序的真实性能,因为在某些情况下,您可能会发现更改意味着性能会变差而不是更好。

较新版本的Python以及Python软件包通常也会表现得更好 - 但是要衡量而不是假设。

注意

除非在特定版本中遇到不寻常的性能问题,否则通常会在新版本中发现更好的功能,可靠性和安全性,而且这些好处远胜于您可能赢或输的任何性能。

Django模板语言的替代品

对于几乎所有的情况,Django的内置模板语言已经足够了。 但是,如果Django项目中的瓶颈似乎存在于模板系统中,并且您已经用尽了其他方法来解决这个问题,那么第三方的替代方案可能就是答案。

Jinja2 can offer performance improvements, particularly when it comes to speed.

替代模板系统在共享Django模板语言的程度上有所不同。

注意

If you experience performance issues in templates, the first thing to do is to understand exactly why. 使用替代的模板系统可能会更快,但同样的收益也可以在不出现这种麻烦的情况下实现 - 例如,模板中昂贵的处理和逻辑可以在您的视图中更高效地完成。

替代软件实现

您可能需要检查一下您使用的Python软件是否提供了另外一种可以更快地执行相同代码的实现。

然而:编写良好的Django站点中的大多数性能问题不在Python执行级别,而在于低效的数据库查询,缓存和模板。 如果您依赖于编写得不好的Python代码,那么您的性能问题不可能通过更快地执行来解决。

使用替代实现可能会引入兼容性,部署,可移植性或维护问题。 毫无疑问,在采用非标准实施之前,您应该确保为您的应用程序提供足够的性能收益,使其超过潜在的风险。

有了这些警告,你应该知道:

PyPy T0> ¶ T1>

PyPy is an implementation of Python in Python itself (the ‘standard’ Python implementation is in C). PyPy可以提供显着的性能提升,通常用于重量级应用程序。

A key aim of the PyPy project is compatibility with existing Python APIs and libraries. Django是兼容的,但你需要检查你依赖的其他库的兼容性。

Python库的C实现

一些Python库也在C中实现,并且可以更快。 他们的目标是提供相同的API。 请注意,兼容性问题和行为差异不是未知的(并不总是立即显而易见)。