Skip to main content

性能和优化

本文档提供了有助于使您的Django代码更高效,更快地运行,并使用更少系统资源的技术和工具的概述。

介绍

通常,人们首先关心的是编写 works 的代码,它的逻辑函数按需要产生预期的输出。然而,有时,这将不足以使代码像 efficiently 一样工作。

在这种情况下,需要的是一些东西 - 实际上,通常是一系列的东西 - 来提高代码的性能,而不会或只是最低限度地影响其行为。

一般方法

你在优化 for 是什么?

重要的是有一个清晰的概念,你的意思是“性能”。它不只有一个指标。

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

一个领域的改进往往会带来另一个领域的改进,但并不总是如此;有时甚至可以牺牲另一个。例如,程序速度的提高可能导致它使用更多的内存。更糟糕的是,它可以是自我毁灭的 - 如果速度的改善是如此内存饥饿,系统开始耗尽内存,你会做更多的危害比好。

还有其他权衡要考虑。你自己的时间是宝贵的资源,比CPU时间更珍贵。一些改进可能太难以实现,或者可能影响代码的可移植性或可维护性。并非所有的性能改进都值得付出努力。

所以,你需要知道你的目标是什么性能改进,你还需要知道,你有一个很好的理由,瞄准这个方向,因为你需要:

性能基准

这不是只是猜测或假设在你的代码中的低效率。

Django工具

django-debug-toolbar 是一个非常方便的工具,提供洞察你的代码是做什么,以及花费多少时间做它。特别是它可以显示你的页面生成的所有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 }}

一般来说,最适合的工作级别是编码最舒适的最低级别。

注解

以上示例仅仅是说明性的。

首先,在现实生活中,你需要考虑你的计数之前和之后发生的事情,以确定什么是做 在该特定上下文中 的最佳方法。数据库优化文档描述了 在模板中计数会更好的情况

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

缓存

通常,计算值是昂贵的(即资源匮乏和缓慢),因此将值保存到可快速访问的缓存中可能有巨大的好处,为下次需要准备就绪。

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

缓存框架

Django的 缓存框架 通过保存动态内容以便不需要为每个请求计算,从而为性能提高提供了非常重要的机会。

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

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

cached_property

通常必须多次调用类实例方法。如果这个功能是昂贵的,那么这样做可能是浪费。

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

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

了解懒惰

Laziness 是缓存的补充策略。缓存通过保存结果避免重新计算;懒惰延迟计算,直到它实际需要。

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

例如,延迟翻译 可以在目标语言甚至已知之前使用,因为它不会发生,直到实际需要翻译的字符串,例如在呈现的模板中。

懒惰也是一种通过试图避免工作来节省努力的方式。也就是说,懒惰的一个方面是不做任何事情,直到它必须做,因为它可能不会证明是必要的。因此,懒惰可能具有性能影响,并且相关工作越昂贵,通过懒惰获得的就越多。

Python提供了许多用于延迟评估的工具,特别是通过 发电机生成器表达式 构造。值得一读的是Python中的懒惰,以发现在代码中使用延迟模式的机会。

懒惰在Django

Django本身相当懒惰。一个很好的例子可以在 QuerySets 的评估中找到。 QuerySets是惰性的。因此,可以创建 QuerySet,传递并与其他 QuerySets 组合,而不实际引起任何到数据库的访问以获取其描述的项目。传递的是 QuerySet 对象,而不是最终需要从数据库中获取的项目集合。

另一方面,某些操作将强制执行QuerySet的求值。避免对 QuerySet 的过早评估可以节省对数据库的昂贵和不必要的访问。

Django还提供了一个 keep_lazy() 装饰器。这允许使用延迟参数调用的函数本身行为迟缓,只有在需要时才进行求值。因此,懒惰的论据 - 可能是一个昂贵的论点 - 不会被要求进行评估,直到它是严格要求。

数据库

数据库优化

Django的数据库层提供了各种方法来帮助开发人员从他们的数据库获得最佳性能。 数据库优化文档 收集到相关文档的链接,并添加了各种提示,概述了在尝试优化数据库使用时需要采取的步骤。

HTTP性能

中间件

Django附带了一些有用的 中间件 部分,可以帮助优化您的网站的性能。他们包括:

ConditionalGetMiddleware

添加对现代浏览器的支持,以有条件地获取基于 ETagLast-Modified 头的响应。

GZipMiddleware

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

会话

使用缓存会话

使用缓存会话 可以是通过消除从诸如数据库的较慢存储源加载会话数据的需要并且代替地将经常使用的会话数据存储在存储器中来增加性能的方式。

静态文件

静态文件,根据定义是不动态的,使优化增益的一个优秀的目标。

CachedStaticFilesStorage

通过利用Web浏览器的缓存功能,您可以在初始下载后完全消除给定文件的网络匹配。

CachedStaticFilesStorage静态文件 的文件名中附加了一个内容相关的标签,以使浏览器能够安全地对其进行长期缓存,而不会丢失未来的更改 - 当文件更改时,标签也将更改,因此浏览器将自动重新加载资源。

“缩小”

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

模板性能

注意:

  • 使用 {% block %} 比使用 {% include %} 更快

  • 从许多小块组装的重碎片模板可能会影响性能

缓存的模板加载器

启用 cached template loader 通常会大幅提高性能,因为它避免在每次需要渲染时编译每个模板。

使用不同版本的可用软件

有时可能需要检查您使用的软件的不同且性能更好的版本是否可用。

这些技术面向更高级的用户,他们希望提高已经优化的Django站点的性能边界。

然而,他们不是性能问题的魔法解决方案,并且他们不可能带来比边际收益更好的网站,没有已经做正确的方法更基础的事情。

注解

值得重复:达到您已经使用的软件的替代品从来不是性能问题的第一个答案。当您达到这种优化水平时,您需要一个正式的基准解决方案。

较新的经常,但不总是更好

很少有新版本的维护良好的软件效率较低,但是维护人员无法预期每一种可能的用例 - 因此,虽然知道较新的版本可能性能更好,但不要简单地假设它们一直会。

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

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

注解

除非您在特定版本中遇到了异常的性能问题,否则在新版本中通常会找到更好的功能,可靠性和安全性,这些优点远远大于您可能获胜或失败的任何性能。

Django模板语言的替代方法

对于几乎所有情况,Django的内置模板语言是完全足够的。然而,如果你的Django项目的瓶颈似乎在于模板系统,你已经用尽了其他机会来弥补这一点,第三方替代品可能是答案。

Jinja2 可以提供性能改进,特别是在速度方面。

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

注解

If 你在模板中遇到性能问题,首先要做的是明白为什么。使用替代模板系统可能会更快,但是也可以获得相同的收益,而不会遇到麻烦 - 例如,您的模板中的昂贵的处理和逻辑可以更有效地在您的视图中。

替代软件实现

可能值得检查您使用的Python软件是否已在不同的实施中提供,可以更快地执行相同的代码。

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

使用替代实现可以引入兼容性,部署,可移植性或维护问题。不言而喻,在采用非标准实施之前,您应该确保它为您的应用程序提供足够的性能增益,超过潜在的风险。

记住这些注意事项,您应该注意:

PyPy

PyPy 是Python中Python本身的实现(“标准”Python实现是在C中)。 PyPy可以提供重大的性能提升,通常用于重量级应用程序。

PyPy项目的一个关键目标是 兼容性 和现有的Python API和库。 Django是兼容的,但你需要检查你依赖的其他库的兼容性。

C实现的Python库

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