Производительность и оптимизация¶
В этом документе представлен обзор методов и инструментов, которые помогут повысить эффективность и скорость работы вашего кода Django с использованием меньшего количества системных ресурсов.
Описание¶
Обычно первая задача состоит в том, чтобы написать код, который работает, логика которого функционирует так, как требуется для получения ожидаемого результата. Однако иногда этого бывает недостаточно, чтобы код работал так эффективно, как хотелось бы.
В этом случае необходимо что-то (а на практике часто совокупность вещей) для улучшения производительности кода, не влияя или лишь минимально влияя на его поведение.
Общие подходы¶
Для чего вы оптимизируете для?¶
Важно иметь четкое представление о том, что вы подразумеваете под «производительностью». Для этого существует не один показатель.
Повышение скорости может быть наиболее очевидной целью программы, но иногда могут потребоваться другие улучшения производительности, такие как снижение потребления памяти или меньшие требования к базе данных или сети.
Улучшения в одной области часто приводят к улучшению производительности в другой, но не всегда; иногда одно может быть даже за счет другого. Например, повышение скорости программы может привести к тому, что она будет использовать больше памяти. Хуже того, это может оказаться обреченным на провал: если повышение скорости настолько требует памяти, что системе начинает не хватать памяти, вы принесете больше вреда, чем пользы.
Следует иметь в виду и другие компромиссы. Ваше собственное время — ценный ресурс, более ценный, чем время процессора. Некоторые улучшения могут оказаться слишком сложными, чтобы их стоило реализовывать, или могут повлиять на переносимость или удобство сопровождения кода. Не все улучшения производительности стоят затраченных усилий.
Итак, вам нужно знать, к какому повышению производительности вы стремитесь, а также знать, что у вас есть веская причина стремиться в этом направлении, а для этого вам нужно:
Сравнительный анализ производительности¶
Бесполезно просто гадать или предполагать, в чем заключается неэффективность вашего кода.
Инструменты Джанго¶
django-debug-toolbar — очень удобный инструмент, который дает представление о том, что делает ваш код и сколько времени он на это тратит. В частности, он может показать вам все SQL-запросы, которые генерирует ваша страница, и сколько времени занял каждый из них.
Для панели инструментов также доступны сторонние панели, которые могут (например) сообщать о производительности кэша и времени отрисовки шаблона.
Сторонние сервисы¶
Существует ряд бесплатных сервисов, которые будут анализировать и составлять отчеты о производительности страниц вашего сайта с точки зрения удаленного HTTP-клиента, фактически имитируя работу реального пользователя.
Они не могут сообщить о внутренней части вашего кода, но могут дать полезную информацию об общей производительности вашего сайта, включая аспекты, которые невозможно адекватно измерить в среде Django.
Существует также несколько платных сервисов, которые выполняют аналогичный анализ, в том числе некоторые из них поддерживают Django и могут интегрироваться с вашей кодовой базой для более полного профилирования ее производительности.
Сделайте все правильно с самого начала¶
Некоторая работа по оптимизации включает в себя устранение недостатков производительности, но часть работы может быть встроена в то, что вы все равно будете делать, как часть передового опыта, который вам следует принять еще до того, как вы начнете думать об улучшении производительности.
В этом отношении Python — отличный язык для работы, поскольку решения, которые выглядят элегантно и кажутся правильными, обычно являются наиболее эффективными. Как и в случае с большинством навыков, изучение того, что «выглядит правильно», требует практики, но одно из наиболее полезных правил таково:
Работа на должном уровне¶
Django предлагает множество различных подходов к решению задач, но тот факт, что можно сделать что-то определенным образом, не означает, что это наиболее подходящий способ. Например, вы можете обнаружить, что можете вычислить одно и то же — например, количество элементов в коллекции — в QuerySet, в Python или в шаблоне.
However, it will almost always be faster to do this work at lower rather than higher levels. На более высоких уровнях системе приходится иметь дело с объектами через несколько уровней абстракции и уровней механизмов.
То есть база данных обычно может делать что-то быстрее, чем 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 также имеют собственные функции кэширования; они обсуждаются ниже в разделах, посвященных этим компонентам.
Понимание лени¶
Лень — это стратегия, дополняющая кэширование. Кэширование позволяет избежать повторных вычислений за счет сохранения результатов; лень откладывает вычисления до тех пор, пока они действительно не потребуются.
Ленивость позволяет нам ссылаться на вещи до того, как они будут созданы или даже до того, как их можно будет создать. Это имеет множество применений.
Например, lazy Translation можно использовать еще до того, как станет известен целевой язык, поскольку этого не происходит до тех пор, пока действительно не потребуется переведенная строка, например, в отображаемом шаблоне.
Лень — это также способ сэкономить усилия, пытаясь вообще избежать работы. То есть один из аспектов лени — не делать ничего до тех пор, пока это не будет сделано, потому что в конце концов может оказаться, что это не нужно. Таким образом, лень может иметь последствия для производительности, и чем дороже соответствующая работа, тем больше выгоды можно получить от лени.
Python предоставляет ряд инструментов для отложенных вычислений, в частности, с помощью конструкций generator и generator Expression. Стоит прочитать о лени в Python, чтобы открыть для себя возможности использования ленивых шаблонов в вашем коде.
Лень в Джанго¶
Джанго сам по себе довольно ленив. Хороший пример этого можно найти в оценке QuerySets. Наборы запросов ленивы. Таким образом, QuerySet может быть создан, передан и объединен с другими QuerySets, без каких-либо обращений к базе данных для получения описываемых ею элементов. Передается объект QuerySet, а не набор элементов, которые в конечном итоге потребуются из базы данных.
С другой стороны, определенные операции приведут к принудительной оценке QuerySet. Избегая преждевременной оценки QuerySet, можно избежать дорогостоящего и ненужного обращения к базе данных.
Django также предлагает декоратор keep_lazy(). Это позволяет функции, вызванной с ленивым аргументом, вести себя лениво, вычисляясь только тогда, когда это необходимо. Таким образом, ленивый аргумент, который может быть дорогостоящим, не будет использоваться для оценки до тех пор, пока он не будет строго необходим.
Базы данных¶
Оптимизация базы данных¶
Уровень базы данных Django предоставляет различные способы помочь разработчикам добиться максимальной производительности своих баз данных. В документации по оптимизации базы данных собраны ссылки на соответствующую документацию и добавлены различные советы, описывающие шаги, которые необходимо предпринять при попытке оптимизировать использование базы данных.
Производительность HTTP¶
Промежуточный слой (Middleware)¶
Django поставляется с несколькими полезными компонентами промежуточного программного обеспечения, которые могут помочь оптимизировать производительность вашего сайта. Они включают в себя:
ConditionalGetMiddleware¶
Добавляет поддержку современных браузеров для условного получения ответов на основе заголовков ETag и Last-Modified. Он также вычисляет и устанавливает ETag, если необходимо.
GZipMiddleware¶
Сжимает ответы для всех современных браузеров, экономя полосу пропускания и время передачи. Обратите внимание, что GZipMiddleware в настоящее время считается угрозой безопасности и уязвим для атак, которые сводят на нет защиту, обеспечиваемую TLS/SSL. Дополнительную информацию смотрите в предупреждении в GZipMiddleware.
Сессии¶
Использование кэша для хранения сессии¶
Использование кэшированных сессий может быть способом повысить производительность за счет устранения необходимости загружать данные сеанса из более медленного источника хранения, такого как база данных, и вместо этого хранить часто используемые данные сеанса в памяти.
Статические файлы¶
Статические файлы, которые по определению не являются динамическими, являются отличной целью для оптимизации.
ManifestStaticFilesStorage¶
Воспользовавшись возможностями кэширования веб-браузеров, вы можете полностью исключить попадание в сеть для данного файла после первоначальной загрузки.
ManifestStaticFilesStorage добавляет тег, зависящий от содержимого, к именам файлов статических файлов, чтобы браузеры могли безопасно кэшировать их в течение длительного времени, не пропуская будущие изменения - при изменении файла изменится и тег, поэтому браузеры автоматически перезагрузят ресурс.
«Минификация»¶
Несколько сторонних инструментов и пакетов Django предоставляют возможность «минимизировать» HTML, CSS и JavaScript. Они удаляют ненужные пробелы, переводы строк и комментарии, а также сокращают имена переменных и, таким образом, уменьшают размер документов, публикуемых вашим сайтом.
Производительность шаблона¶
Обратите внимание, что:
использование
{%block %}быстрее, чем использование{% include %}сильно фрагментированные шаблоны, собранные из множества мелких частей, могут влиять на производительность
Загрузчик кэшированных шаблонов¶
Включение кэшированного загрузчика шаблонов часто значительно повышает производительность, поскольку позволяет избежать компиляции каждого шаблона каждый раз, когда его необходимо отобразить.
Использование разных версий доступного программного обеспечения¶
Иногда стоит проверить, доступны ли другие, более производительные версии используемого вами программного обеспечения.
Эти методы предназначены для более опытных пользователей, которые хотят расширить границы производительности и без того хорошо оптимизированного сайта Django.
Однако они не являются волшебным решением проблем с производительностью, и они вряд ли принесут большую, чем минимальную, выгоду сайтам, которые еще не делают более простые вещи правильно.
Примечание
Стоит повторить: поиск альтернатив программному обеспечению, которое вы уже используете, никогда не является первым решением проблем с производительностью. Когда вы достигнете этого уровня оптимизации, вам понадобится формальное решение для сравнительного анализа.
Новее часто (но не всегда) лучше¶
Довольно редко новая версия хорошо поддерживаемого программного обеспечения оказывается менее эффективной, но сопровождающие не могут предусмотреть все возможные варианты использования, поэтому, зная, что новые версии, скорее всего, будут работать лучше, не думайте, что так будет всегда.
Это справедливо и для самого Django. Последующие выпуски предлагали ряд улучшений во всей системе, но вам все равно следует проверять реальную производительность вашего приложения, поскольку в некоторых случаях вы можете обнаружить, что изменения означают, что оно работает хуже, а не лучше.
Новые версии Python, а также пакеты Python часто работают лучше, но измеряйте, а не предполагайте.
Примечание
Если вы не столкнулись с необычной проблемой производительности в конкретной версии, вы, как правило, обнаружите лучшие функции, надежность и безопасность в новой версии, и эти преимущества гораздо более значимы, чем любая производительность, которую вы можете выиграть или потерять.
Альтернативы языку шаблонов Django¶
Почти во всех случаях встроенный язык шаблонов Django вполне достаточен. Однако, если узкие места вашего проекта Django кроются в системе шаблонов и вы исчерпали другие возможности исправить это, решением может стать сторонняя альтернатива.
Jinja2 может предложить повышение производительности, особенно когда дело касается скорости.
Альтернативные системы шаблонов различаются по степени использования языка шаблонов Django.
Примечание
Если у вас возникли проблемы с производительностью в шаблонах, первое, что нужно сделать, — понять, почему именно. Использование альтернативной системы шаблонов может оказаться более быстрым, но те же выгоды можно получить и без этих проблем — например, дорогостоящая обработка и логика в ваших шаблонах могут быть выполнены более эффективно в ваших представлениях.
Альтернативные реализации программного обеспечения¶
Возможно, стоит проверить, предоставлено ли используемое вами программное обеспечение Python в другой реализации, которая может выполнять тот же код быстрее.
Однако большинство проблем с производительностью на хорошо написанных сайтах Django возникают не на уровне выполнения Python, а скорее в неэффективных запросах к базе данных, кэшировании и шаблонах. Если вы полагаетесь на плохо написанный код Python, ваши проблемы с производительностью вряд ли будут решены за счет более быстрого его выполнения.
Использование альтернативной реализации может привести к проблемам совместимости, развертывания, переносимости или обслуживания. Само собой разумеется, что прежде чем принимать нестандартную реализацию, вы должны убедиться, что она обеспечивает достаточный прирост производительности вашего приложения, чтобы перевесить потенциальные риски.
Учитывая эти предостережения, вы должны знать:
PyPy¶
PyPy — это реализация Python в самом Python («стандартная» реализация Python находится на языке C). PyPy может обеспечить существенный прирост производительности, как правило, для тяжелых приложений.
Ключевой целью проекта PyPy является совместимость с существующими API и библиотеками Python. Django совместим, но вам нужно будет проверить совместимость других библиотек, на которые вы полагаетесь.
C-реализации библиотек Python¶
Некоторые библиотеки Python также реализованы на C и могут работать намного быстрее. Они стремятся предложить одни и те же API. Обратите внимание, что проблемы совместимости и различия в поведении не являются чем-то неизвестным (и не всегда очевидны).