Сегодня я хочу поговорить о тормозах, и, как мне кажется, самое медленное место в джанге (помимо кривых рук программистов) это темплейты.
Сам принцип их работы очень напоминает cgi - на каждый запрос мы все делаем заново, заново ищем файл, заново читаем файл (или еще что) и наконец заново компилируем (получаем объект Template).
Конечно на этом работа с темплейтами не заканчивается, сам рендеринг еще не начинался, и основные тормоза как раз в нем, но повторюсь это выполняется на каждый запрос, и это правда не быстро.
Для решения этой проблемы 2 года назад открыли тикет 6262, предлагалось кэшировать темплейты после их первой загрузки, все бы хорошо, и сама задача выглядит не сложной, но есть забавные подводные камни.
Дело в том, что некоторые тэги хранят промежуточные данные в аттрибутах объекта Node, и они не потокобезопасны, например:
{% cycle 'row1' 'row2' %}Поток 1, итерация 1 - 'row1'Поток 2, итерация 1 - 'row2'Поток 1, итерация 2 - 'row1'Поток 2, итерация 2 - 'row2'
Как видно, поведение тэга при одновременной обработке 2 запросов явно отличается от ожидаемого.
Чтобы решить эту, не совсем очевидную проблему, решили хранить переменные тэгов, прямо в объекте контекста.
class CycleNode(Node): def __init__(self, cyclevars): self.cyclevars = cyclevars def render(self, context): if self not in context.render_context: context.render_context[self] = itertools.cycle(self.cyclevars) cycle_iter = context.render_context[self] return cycle_iter.next()
И теперь поведение "cycle" будет таким, как от него ожидается.
Это дало возможность достаточно легко приделать кэширование и еще раз поломать обратную совместимость )
Т.е. тем, кто хочет использовать это кэширование стоит проверить свои тэги на потокобезопасность, а иначе юзер может сильно удивляться обновляя страницу и видя каждый раз новые данные.
Кстати, заодно была переделана сама система загрузки шаблонов.
Раньше было так:
TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.load_template_source', 'django.template.loaders.app_directories.load_template_source',)
А стало:
TEMPLATE_LOADERS = ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader',)
Поменялось совсем чуть-чуть, но в этом чуть-чуть сама соль )
Сейчас это не функции, а классы (ну наконец то!!11) с простым интерфейсом. А старый стиль объявлен устаревшим и будет удален после релиза 1.4
Так вот, чтобы начать использовать кэш, надо только сделать так:
TEMPLATE_LOADERS = ( ('django.template.loaders.cached.Loader', ( 'django.template.loaders.filesystem.Loader', 'django.template.loaders.app_directories.Loader', )),)
И все, больше не будет повторной загрузки темплейта.
Кстати, если у вас свои загрузчики темплейтов, то мигрироваться будет совсем не сложно, все что нам нужно - это переопределить 1 функцию.
class Loader(BaseLoader): is_usable = True def load_template_source(self, template_name, template_dirs=None): pass
Так же как и раньше надо написать load_template_source, которая принимает имя темплейта и возвращает тупл из его текстового содержимого и имени файла.
Ну вот вроде и все )
ps надеюсь было интересно )
Комментариев нет:
Отправить комментарий