Сообщить об ошибке.

Внешнее кэширование байт-кода шаблонов модулем jinja2 в Python

Кэширование шаблонов в FileSystemCache или Memcached

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

Это особенно полезно, если есть веб-приложение, которое инициализируется по первому запросу, а Jinja компилирует сразу несколько шаблонов, что замедляет работу приложения.

Содержание:


jinja2.BytecodeCache():

Чтобы реализовать свой собственный кеш байт-кода, необходимо создать подкласс этого класса и переопределить методы .load_bytecode() и .dump_bytecode(). Оба эти метода передаются в Bucket.

Пример реализации простого кэширования байт-кода, который сохраняет кеш в файловой системе:

# псевдокод
from os import path

MyCache(BytecodeCache):

    def __init__(self, directory):
        self.directory = directory

    def load_bytecode(self, bucket):
        filename = path.join(self.directory, bucket.key)
        if path.exists(filename):
            with open(filename, 'rb') as f:
                bucket.load_bytecode(f)

    def dump_bytecode(self, bucket):
        filename = path.join(self.directory, bucket.key)
        with open(filename, 'wb') as f:
            bucket.write_bytecode(f)

Более продвинутая версия кэша байт-кода на основе файловой системы является частью API Jinja.

Методы объекта BytecodeCache:

BytecodeCache.clear():

Метод BytecodeCache.clear() очищает кеш. Этот метод не используется Jinja, но должен быть реализован, чтобы позволить приложениям очищать кеш байт-кода, используемый конкретной средой.

BytecodeCache.dump_bytecode(bucket):

Метод BytecodeCache.dump_bytecode() подклассы должны переопределить этот метод, чтобы записать байт-код из сегмента хранения Bucket обратно в кеш. Если он не может этого сделать, то метод обязательно должен вызвать исключение.

BytecodeCache.load_bytecode(bucket):

Метод BytecodeCache.load_bytecode() подклассы должны переопределить этот метод для загрузки байт-кода в сегмент хранения Bucket. Если они не могут найти код в кэше для сегмента, то метод должен ничего делать.

jinja2.bccache.Bucket(environment, key, checksum):

Сегменты Bucket используются для хранения байт-кода одного шаблона. Он создается и инициализируется кэшем байт-кода и передается функциям загрузки.

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

Методы объекта Bucket:

Bucket.environment:

Атрибут Bucket.environment - это среда, создавшая сегмент.

Bucket.key:

Атрибут Bucket.key представляет собой уникальный ключ кэша для этого сегмента.

Bucket.code:

Атрибут Bucket.code - байт-код, если он загружен, в противном случае - None.

Bucket.bytecode_from_string(string):

Метод Bucket.bytecode_from_string() загружает байт-код из строки.

Bucket.bytecode_to_string():

Метод Bucket.bytecode_to_string() возвращает байт-код в виде строки.

Bucket.load_bytecode(f):

Метод Bucket.load_bytecode() загружает байт-код из файла или файлоподобного объекта.

Bucket.reset():

Метод Bucket.reset() сбрасывает сегмент хранения (выгружает байт-код).

Bucket.write_bytecode(f):

Метод Bucket.write_bytecode() выгружает байт-код в файл или файлоподобный объект.

Встроенные классы кэширования байт-кода в модуль jinja2:

Чтобы использовать кеш байт-кода, создайте экземпляр нужного класса и передайте в Environment.

jinja2.FileSystemBytecodeCache(directory=None, pattern='__jinja2_%s.cache'):

Класс jinja2.FileSystemBytecodeCache() представляет собой кэш байт-кода, который хранится в файловой системе. Класс принимает два аргумента: directory, в котором хранятся элементы кэша, и строка шаблона pattern, используемая для создания имени файла.

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

Шаблон может использоваться для работы нескольких отдельных кэшей в одном каталоге. Шаблон по умолчанию - "__jinja2_%s.cache", где %s заменяется ключом кэша.

>>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache')

Этот кэш байт-кода поддерживает очистку кэша с помощью метода .clear().

jinja2.MemcachedBytecodeCache(client, prefix='jinja2/bytecode/', timeout=None, ignore_memcache_errors=True):

Класс jinja2.MemcachedBytecodeCache() реализует кэш байт-кода, который использует память для хранения кешированной информации. Он не применяет конкретную библиотеку кэша памяти (memcache или cmemcache), но принимает любой класс, который предоставляет минимальный требуемый интерфейс.

Библиотеки, совместимые с этим классом:

  • cachelib;
  • python-memcached.

(К сожалению, интерфейс кэша django несовместим, потому что он не поддерживает хранение двоичных данных, только Unicode. Однако можно передать базовый клиент кеша в кеш байт-кода, который доступен как django.core.cache.cache._client.)

MinimalClientInterface():

Класс MinimalClientInterface() - это минимальный интерфейс для клиента (аргумент client), передаваемый конструктору jinja2.MemcachedBytecodeCache

Определяемые методы:

  • set(key, value[, timeout]): сохраняет байт-код в кэше. Аргумент value - это строка, а timeout - таймаут ключа key. Если timeout не указан, то используется таймаут по умолчанию или timeout не должен приниматься, если он указан в конструкторе. Аргумент timeout - это целое число с количеством секунд, в течение которых должен существовать элемент кэша.

  • get(key): возвращает значение ключа кэша. Если элемент не существует в кэше, возвращаемое значение должно быть None.

Другими аргументами конструктора являются префикс prefix для всех ключей, который добавляется перед фактическим ключом кеша, и тайм-аут timeout для байт-кода в системе кэширования. Рекомендуется высокий тайм-аут (или его отсутствие).

Этот кэш байт-кода не поддерживает очистку использованных элементов в кэше. Метод .clear() здесь ничего не делает.