Подтвердить что ты не робот

Django - рендеринг многих шаблонов с использованием templatetags очень медленный

Скажем, у меня есть страница с фотогалереей. Каждый эскиз имеет, например, фотография, страна, автор и т.д. Я переношу эти элементы/виджеты с помощью шаблонных тегов (которые загружают указанные шаблоны) - это происходит из-за DRY (я использую эти элементы/виджеты отдельно в разных местах на странице).

И это очень медленно.

Я выполнил некоторые профилирования с помощью панели инструментов django-debug:

SQL Queries: default 84.81 ms (147 queries)

Но:

Total CPU time: 5768.360 msec

Слишком долго ждать.

После некоторого анализа выяснилось, что основным виновником является замаскивание шаблонов.

Когда я хочу отобразить, например. 150 фотографий, 600 связанных элементов/виджетов обрабатываются с помощью шаблонов. Это означает 600 операций ввода-вывода или даже больше. Перемещение этих виджетов на главный шаблон решает проблему, но не сохраняет DRY.

Итак, мой вопрос в том, как можно избежать такого поведения? Быть сухим и медленным или не сухим и быстрым? Я предпочел бы быть сухим и быстрым...

4b9b3361

Ответ 1

После нескольких часов профилирования и поиска...

Спасибо за вашу помощь, но в этом случае мне кажется, что лучшим решением до сих пор является кэширование фрагментов шаблонов:

Я попробовал и получил скорость 70-80%!

{% load cache %}
{% cache 3600 mywidget_id %}
    .. rendered mywidget is cached ..
{% endcache %}

Ответ 2

Возможно, вы захотите попробовать загрузчик шаблонов кэширования, django.template.loaders.cached.Loader - он, безусловно, должен уменьшить количество требуемого ввода-вывода.

Изменить для добавления. Вы должны быть осторожны, полагая, что только потому, что большая часть времени проводится на этапе визуализации шаблона, то количество запросов не должно винить. Не забывайте, что запросы являются ленивыми, и если вы специально не нарезаете или не повторяете их в представлении, они будут оцениваться только при загрузке шаблона. Я бы сказал, что сокращение количества запросов с помощью хорошего использования select_related и других методов должно быть значительной помощью.

Ответ 3

Я предполагаю, что вы используете панель инструментов отладки, в которой вы получаете эти числа в процессе разработки. Однако из-за этого они не являются "реальными" числами.

Встроенный сервер Django хорош для разработки, но он имеет ряд недостатков, которые делают его намного медленнее, чем настоящий веб-сервер. Во-первых, это однопоточная, поэтому это означает отсутствие параллельных запросов. Это также означает, что операции ввода-вывода дискретны. Во-вторых, ему поручено не просто обслуживать запросы Django, но и статические ресурсы.

Длинные и короткие, если вы хотите по-настоящему профилировать свой сайт для загрузки страниц, вам нужно установить настоящий веб-сервер локально. В основном это настроено так, как в вашей производственной среде. Тогда я был бы готов заявить, что время запроса будет намного лучше.

Ответ 4

Это может не относиться к этой конкретной проблеме, но в некоторых случаях это помогло мне использовать select_related в запросах. Возможно, это не так, но это может снизить количество запросов.

Ответ 5

Время, затраченное на запросы, относительно невелико. Но ORM занимает гораздо больше времени, чтобы сгенерировать эти запросы и проанализировать результаты в экземплярах модели.

Итак, несмотря на огромное количество запросов, ваше приложение связано с CPU из-за медленной ORM (в вашем случае это может занять некоторое время). Таким образом, вы все равно должны сократить количество запросов.

Скорее всего, запросы создаются внутри вашего тега шаблона. Поэтому вам нужно получить нужные данные в нескольких запросах и установить их на экземплярах фотографий.

{% for photo in photos|annotate_comment_count %}
   ...
{% endfor %}

def annotate_comment_count(photo_list):
    counts = dict(Comment.objects.filter(photo__in=photo_list).values('photo') \
                                 .annotate(count=models.Count('id')))
    for photo in photo_list:
        photo.comments_count = counts[photo.pk]
    return photo_list

Итак, внутри вашего templatetag вам не нужно запрашивать количество комментариев для одной фотографии, но у вас уже есть эта информация в атрибуте comments_count. И вы достигли этого в одном запросе.

Ответ 6

У меня была такая же проблема, и, возможно, по той же причине. Я оптимизировал производительность настраиваемого тега шаблона. Количество запросов db уменьшилось с 640 до 2, и полученное время db составляло менее 20 мс. Однако моя страница стала медленнее! 7 с → 10 с. Вздох. Я попробовал кэшированный загрузчик шаблонов без эффекта.

Я отказался, отключил панель инструментов отладки django, после чего время отклика упало до 1,2 с, невероятно!! В моем случае огромное время отклика было вызвано только панелью отладки! Связанную с этим проблему можно найти здесь. Я не погружаюсь глубже в эту проблему с панелью инструментов, так как я планировал кэшировать тег шаблона с помощью кэширования фрагментов шаблона в любом случае. Во время разработки у меня время отклика 10 с каждые 15 минут, с которыми я могу жить. В любом случае, надеюсь, что это поможет.