Производительность и оптимизация
В этом документе представлен обзор методов и инструментов, которые помогут сделать ваш код Django более эффективным — быстрее и с меньшим использованием системных ресурсов.
Введение
Обычно первоочередной задачей является создание работающего кода, логика которого функционирует в соответствии с требованиями для получения ожидаемого результата. Однако иногда этого недостаточно, чтобы код работал так эффективно, как хотелось бы.
В этом случае необходимо что-то — а на практике часто и набор чего-то — для улучшения производительности кода без или с минимальным влиянием на его поведение.
Общие подходы
Для чего вы оптимизируете?
Важно иметь четкое представление о том, что вы понимаете под «производительностью». Нет единого показателя.
Увеличение скорости может быть самой очевидной целью программы, но иногда могут быть необходимы и другие улучшения производительности, например, меньшее потребление памяти или меньшая нагрузка на базу данных или сеть.
Улучшения в одной области часто приводят к улучшению производительности в другой, но не всегда; иногда одно может даже идти в ущерб другому. Например, улучшение скорости программы может привести к большему потреблению памяти. Хуже того, это может быть самоуничтожающим — если улучшение скорости настолько требует памяти, что система начинает испытывать недостаток памяти, вы навредите больше, чем поможете.
Есть и другие компромиссы, которые следует учитывать. Ваше собственное время является ценным ресурсом, более важным, чем время процессора. Некоторые улучшения могут быть слишком сложными, чтобы оправдывать их внедрение, или могут повлиять на переносимость или поддержку кода. Не все улучшения производительности стоят усилий.
Итак, вам нужно знать, какие улучшения производительности вы хотите получить, и у вас должна быть веская причина для этого — и для этого вам нужно:
Измерение производительности
Нельзя просто угадывать или предполагать, где лежат неэффективности в вашем коде.
Инструменты Django
django-debug-toolbar — очень полезный инструмент, который предоставляет информацию о том, что делает ваш код и сколько времени он тратит на это. В частности, он может показать вам все SQL-запросы, генерируемые вашей страницей, и сколько времени занял каждый из них.
Для панели также доступны сторонние модули, которые могут (например) сообщать о производительности кэша и времени рендеринга шаблонов.
Сервисы сторонних разработчиков
Существует ряд бесплатных сервисов, которые будут анализировать и сообщать о производительности страниц вашего сайта с точки зрения удаленного HTTP-клиента, фактически имитируя опыт реального пользователя.
Они не могут сообщать о внутренностях вашего кода, но могут предоставить полезную информацию о общей производительности вашего сайта, включая аспекты, которые нельзя должным образом измерить изнутри среды Django.
Также существуют платные сервисы, которые выполняют аналогичный анализ, включая некоторые, которые учитывают Django и могут интегрироваться в ваш код для более всеобъемлющего профилирования его производительности.
Сделайте все правильно с самого начала
Некоторая работа по оптимизации включает в себя устранение недостатков производительности, но некоторые из этих работ можно встроить в то, что вы делаете и так, как часть хороших практик, которые вы должны использовать даже до того, как начнете думать об улучшении производительности.
В этом отношении Python — отличный язык для работы, потому что решения, которые выглядят элегантно и правильными, как правило, являются лучшими с точки зрения производительности. Как и в большинстве навыков, освоение того, что «выглядит правильно», требует практики, но одним из самых полезных руководств является:
Работайте на надлежащем уровне
Django предлагает множество способов подхода к задачам, но только потому, что что-то можно сделать определенным способом, не значит, что это самый подходящий способ. Например, вы можете обнаружить, что можете рассчитать одно и то же — количество элементов в коллекции, возможно — в базе данных, на Python или в шаблоне.
Однако, это почти всегда будет быстрее, если выполнять эту работу на более низких, а не на более высоких уровнях. На более высоких уровнях система должна обрабатывать объекты через несколько уровней абстракции и слоев механизмов.
То есть база данных, как правило, может делать вещи быстрее, чем 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 также имеют собственную функциональность кэширования; они обсуждаются ниже в разделах, связанных с этими компонентами.
Понимание лени
Лени — это стратегия, дополняющая кэширование. Кэширование избегает повторного вычисления, сохраняя результаты; лень откладывает вычисление до тех пор, пока это не потребуется.
Лени позволяет ссылаться на вещи до их создания или даже до того, как их можно создать. Это имеет множество применений.
Например, отложенный перевод можно использовать до того, как будет известен целевой язык, потому что он не выполняется до тех пор, пока переведенная строка фактически не потребуется, например, в рендеренном шаблоне.
Лени также является способом экономии усилий, пытаясь избежать работы в первую очередь. То есть, один из аспектов лени — не делать ничего, пока это не нужно сделать, потому что это может оказаться необязательным. Поэтому лени может иметь последствия для производительности, и чем дороже работа, тем больше можно выиграть, используя ленивые подходы.
Python предоставляет ряд инструментов для ленивой оценки, особенно через конструкции генератора и генераторного выражения. Стоит ознакомиться с лени в Python, чтобы обнаружить возможности использования ленивых шаблонов в вашем коде.
Ленивость в Django
Django сам по себе довольно ленивый. Хороший пример этого можно найти в оценке QuerySets. QuerySets — ленивые. Таким образом, можно создать QuerySet, передавать его и комбинировать с другими QuerySets, не производя фактических обращений к базе данных для извлечения элементов, которые он описывает. Передаваемым объектом является QuerySet, а не коллекция элементов, которые — в конечном итоге — будут необходимы из базы данных.
С другой стороны, некоторые операции будут принудительно оценивать QuerySet. Избегание преждевременной оценки QuerySet может сэкономить дорогостоящую и ненужную поездку в базу данных.
Django также предлагает декоратор keep_lazy(). Это позволяет функции, которая была вызвана с ленивым аргументом, вести себя лениво, оцениваясь только тогда, когда это необходимо. Таким образом, ленивый аргумент — который может быть дорогостоящим — не будет вызываться для оценки до тех пор, пока это не будет строго необходимо.
Базы данных
Оптимизация базы данных
Слой базы данных Django предоставляет различные способы, которые помогут разработчикам получить наилучшую производительность от своих баз данных. Документация по оптимизации базы данных собирает ссылки на соответствующую документацию и добавляет различные советы, которые описывают шаги, которые необходимо предпринять при попытке оптимизировать использование вашей базы данных.
Производительность HTTP
Средства промежуточного слоя
Django поставляется с несколькими полезными средствами средств промежуточного слоя, которые могут помочь оптимизировать производительность вашего сайта. Они включают в себя:
ConditionalGetMiddleware
Добавляет поддержку современным браузерам для условного получения ответов на основе заголовков ETag и Last-Modified. Также вычисляет и устанавливает тег ETag при необходимости.
GZipMiddleware
Сжимает ответы для всех современных браузеров, экономя пропускную способность и время передачи. Обратите внимание, что GZipMiddleware в настоящее время рассматривается как потенциальный риск для безопасности и уязвим для атак, которые уничтожают защиту, обеспечиваемую TLS/SSL. См. предупреждение в GZipMiddleware для получения дополнительной информации.
Сессии
Использование кэшированных сессий
Использование кэшированных сессий может быть способом повышения производительности, устраняя необходимость загрузки данных сессии из медленного источника хранения, такого как база данных, и вместо этого хранение часто используемых данных сессии в памяти.
Статические файлы
Статические файлы, по определению нединамичные, являются отличной целью для повышения производительности.
ManifestStaticFilesStorage
Используя возможности кэширования веб-браузеров, вы можете полностью устранить сетевые запросы для данного файла после первоначальной загрузки.
ManifestStaticFilesStorage добавляет тег, зависящий от содержимого, к именам файлов статических файлов, чтобы браузеры могли кэшировать их в долгосрочной перспективе без пропуска будущих изменений - при изменении файла изменяется и тег, поэтому браузеры автоматически перезагрузят ресурс.
«Минификация»
Несколько сторонних инструментов и пакетов Django предоставляют возможность «минифицировать» HTML, CSS и JavaScript. Они удаляют ненужные пробелы, новые строки и комментарии, укорачивают имена переменных, уменьшая размер документов, публикуемых вашим сайтом.
Производительность шаблонов
Обратите внимание, что:
- использование
{% block %}быстрее, чем использование{% include %} - сильно фрагментированные шаблоны, собранные из множества маленьких фрагментов, могут повлиять на производительность
Кэширующий загрузчик шаблонов
Включение cached template loader часто резко улучшает производительность, так как это позволяет избежать компиляции каждого шаблона каждый раз, когда он должен быть отображён.
Использование различных версий доступного программного обеспечения
Иногда стоит проверить, доступны ли разные и более производительные версии программного обеспечения, которое вы используете.
Эти методы предназначены для более опытных пользователей, которые хотят расширить границы производительности уже хорошо оптимизированного сайта Django.
Однако, они не являются волшебными решениями проблем с производительностью, и вряд ли принесут более чем незначительный прирост производительности сайтам, которые не делают более простых вещей должным образом.
Примечание
Стоит повторить: поиск альтернатив уже используемому программному обеспечению никогда не является первым ответом на проблемы с производительностью. Когда вы достигаете этого уровня оптимизации, вам нужна формальная система оценки производительности.
Новое часто, но не всегда, лучше
Вероятность того, что новая версия хорошо поддерживаемого программного обеспечения будет менее эффективной, довольно мала, но разработчики не могут предусмотреть все возможные варианты использования - поэтому, хотя следует учитывать, что более новые версии, скорее всего, будут работать лучше, не стоит предполагать, что это всегда так.
Это относится и к Django. Последовательные версии предлагают ряд улучшений по всему проекту, но вам всё равно следует проверять реальную производительность вашего приложения, так как в некоторых случаях вы можете обнаружить, что изменения приводят к худшим результатам, а не лучшим.
Более новые версии Python, а также пакетов Python, часто будут работать лучше - но измеряйте, а не предполагайте.
Примечание
Если вы не столкнулись с необычной проблемой производительности в какой-либо конкретной версии, вы обычно найдёте лучшие функции, надёжность и безопасность в новой версии, и эти преимущества значительно более значительны, чем любой выигрыш или потеря производительности.
Альтернативы языку шаблонов Django
Практически во всех случаях встроенный язык шаблонов Django вполне достаточен. Однако, если узкие места в вашем проекте Django, похоже, лежат в системе шаблонов, и вы исчерпали другие возможности для их устранения, сторонняя альтернатива может стать решением.
Jinja2 может обеспечить улучшение производительности, особенно в отношении скорости.
Альтернативные системы шаблонов различаются по степени, в которой они разделяют язык шаблонов Django.
Примечание
Если у вас возникнут проблемы с производительностью в шаблонах, прежде всего необходимо понять, почему. Альтернативная система шаблонов может оказаться быстрее, но те же преимущества могут быть доступны и без этой необходимости - например, дорогостоящая обработка и логика в ваших шаблонах могут быть реализованы более эффективно в ваших представлениях.
Альтернативные реализации программного обеспечения
Стоит проверить, не было ли предоставлено программного обеспечения Python, которое вы используете, в другой реализации, которая может выполнять тот же код быстрее.
Однако: большинство проблем производительности на хорошо написанных сайтах Django не связаны с уровнем выполнения Python, а скорее с неэффективными запросами к базе данных, кешированием и шаблонами. Если вы полагаетесь на плохо написанный код Python, проблемы производительности, скорее всего, не будут решены за счёт его более быстрого выполнения.
Использование альтернативной реализации может привести к проблемам совместимости, развертывания, переносимости или обслуживания. Само собой разумеется, что перед внедрением нестандартной реализации необходимо убедиться, что она обеспечивает достаточный прирост производительности для вашего приложения, чтобы перевесить потенциальные риски.
С учётом этих оговорок, вы должны быть осведомлены о:
PyPy
PyPy — это реализация Python на языке Python (стандартная реализация Python написана на C). PyPy может обеспечить существенный прирост производительности, как правило, для многозадачных приложений.
Ключевая цель проекта PyPy — совместимость с существующими API и библиотеками Python. Django совместим, но вам необходимо проверить совместимость других библиотек, от которых вы зависите.
Реализации библиотек Python на C
Некоторые библиотеки Python также реализованы на C и могут быть намного быстрее. Они стремятся предложить те же API. Обратите внимание, что проблемы совместимости и различия в поведении не являются чем-то неизвестным (и не всегда очевидны).
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.2/topics/performance/