简体中文 English 繁體中文 日本語 Русский
本文为静态镜像,内容以交互版为准 在交互式文档中心打开 →

Система ленивой загрузки модулей

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

Обзор

Система ленивого загрузки модулей является одной из ключевых особенностей ErisPulse. Она работает следующим образом:

Принцип работы

Класс LazyModule

Основой системы ленивой загрузки является класс LazyModule, который является обёрткой, фактически инициализирующей модуль только при первом обращении.

Процесс инициализации

При первом обращении к модулю LazyModule выполняет следующие действия:

  1. Получает информацию о параметрах __init__ класса модуля
  2. Определяет, следует ли передавать ссылку на sdk
  3. Устанавливает атрибут moduleInfo модуля
  4. Для модулей, унаследованных от BaseModule, вызывает метод on_load
  5. Запускает событие жизненного цикла module.init

Событийное ленивое активирование (activate_on)

Note

Эта функция требует ErisPulse 2.8.0+.

Модули с lazy_load=True по умолчанию загружаются только при первом обращении к атрибуту. Если модуль зарегистрировал обработчики команд или событий, традиционный подход предполагает полную загрузку (lazy_load=False). activate_on предоставляет третий вариант: объявить триггер, и при первом совпадающем событии/команде модуль будет автоматически активирован — он не будет постоянно в памяти, но при этом не упустит входной триггер.

from ErisPulse.loaders import ModuleLoadStrategy

class MyModule(BaseModule):
    @staticmethod
    def get_load_strategy():
        return ModuleLoadStrategy(
            lazy_load=True,
            activate_on=[
                # ---- События (пассивные, не требуют участия пользователя)----
                "message",                                    # Тип события: любое сообщение
                {"notice": "group_member_increase"},          # Тип + detail_type
                {"message": ["private", "group"]},            # Тип + несколько detail_type

                # ---- Команды (активные, ввод пользователя, отображаются в Help)----
                {"command": "roll"},                          # Сокращённая форма: имя команды
                {"command": ["roll", "dice"]},                # Список имён команд
                {"command": {                                 # Форма dict (обязательно name)
                    "name": "dice",
                    "help": "Бросить кубик",
                    "usage": "/dice",
                    "group": "Развлечения",
                    "aliases": ["d"],
                    "hidden": False,
                }},
            ],
        )

Параметры команды в формате dict

Формат dict отражает пользовательские параметры декоратора @command(), и используется для регистрации временной команды до загрузки модуля:

Параметр Тип Значение по умолчанию Описание
name str Обязательно Имя команды; должно совпадать с @command(name) в on_load, иначе временная команда будет удалена при активации, и команда не будет доступна
help str Цепочка возврата Описание команды в Help; если не указано, используется цепочка возврата (см. ниже)
usage str Автоматически Пример использования, по умолчанию {prefix}{name}
group str None Группа команды
aliases list[str] [] Список алиасов, также регистрируется, ввод алиаса также активирует модуль
hidden bool False Если True, временная команда будет скрыта (семантика скрытости совпадает с активированной командой); пользователи, знающие имя команды, могут активировать её

Не поддерживается priority / permission / master: временная команда предназначена только для активации, проверка прав осуществляется активированной командой (в момент активации проверка прав прерывает активацию).

Цепочка возврата для Help временной команды

Описание команды в Help, отображаемое до загрузки модуля, берётся по следующему порядку (первое найденное значение):

  1. help в команде dict (наиболее точное)
  2. description из get_meta()
  3. __description__ из модуля
  4. Summary из метаданных пакета (краткое описание пакета на PyPI)
  5. Общее сообщение: «Эта команда из лениво загружаемого модуля X, при первом использовании модуль будет автоматически загружен»

Семантика триггеров

Архитектурная диаграмма и полная семантика см. в Обзоре архитектуры.

Конфигурация ленивой загрузки

Глобальная конфигурация

В файле конфигурации включите/отключите глобальную ленивую загрузку:

[ErisPulse.framework]
enable_lazy_loading = true  # true=включить ленивую загрузку (по умолчанию), false=отключить ленивую загрузку

Управление на уровне модуля

Модуль может контролировать стратегию загрузки, реализовав статический метод get_load_strategy():

from ErisPulse.Core.Bases import BaseModule
from ErisPulse.loaders import ModuleLoadStrategy

class MyModule(BaseModule):
    @staticmethod
    def get_load_strategy():
        """Возвращает стратегию загрузки модуля"""
        return ModuleLoadStrategy(
            lazy_load=False,  # Возвращает False для немедленной загрузки
            priority=100      # Приоритет загрузки, чем больше значение, тем выше приоритет
        )

Использование модулей с ленивой загрузкой

Основное использование

Для разработчиков использование модулей с ленивой загрузкой практически не отличается от обычных модулей:

# Доступ к модулю с ленивой загрузкой через SDK
from ErisPulse import sdk

# Следующий вызов инициирует ленивую загрузку модуля
result = await sdk.my_module.my_method()

Единый вход для получения модуля

Независимо от того, получаете ли вы модуль через свойство SDK, свойство менеджера модулей или с помощью module.get(), для "зарегистрированных, но еще не загруженных" модулей с ленивой загрузкой будет возвращаться один и тот же прокси-объект ленивой загрузки. Инициализация происходит только при обращении к его свойствам:

# Все три способа возвращают один и тот же прокси-объект ленивой загрузки (когда модуль еще не загружен), поведение одинаково и для пользователя прозрачно
sdk.my_module          # Точка входа для инициации загрузки
sdk.module.my_module   # Также возвращает прокси-объект ленивой загрузки
sdk.module.get("my_module")  # Также возвращает прокси-объект ленивой загрузки, сам вызов не инициирует загрузку

# Инициализация модуля происходит только при обращении к свойству прокси-объекта
result = await sdk.my_module.my_method()

module.get() — это интерфейс для запроса, сам вызов не инициирует загрузку:

Если необходимо явно инициировать загрузку, используйте await sdk.load_module("my_module").

Асинхронная инициализация

Для модулей, требующих асинхронной инициализации, рекомендуется сначала явно загрузить модуль:

# Сначала явно загрузите модуль
await sdk.load_module("my_module")

# Затем используйте модуль
result = await sdk.my_module.my_method()

Синхронная инициализация

Для модулей, не требующих асинхронной инициализации, можно обращаться напрямую:

# Прямое обращение автоматически инициирует синхронную инициализацию
result = sdk.my_module.some_sync_method()

Рекомендуемые практики

При выборе стратегии загрузки можно использовать следующий процесс принятия решений:

flowchart TD
    A["Объявление модуля<br/>get_load_strategy()"] --> B{"Требуется готовность при запуске<br/>или частое срабатывание?"}
    B -->|"Да"| C["lazy_load=False<br/>Загрузка немедленно"]
    B -->|"Нет"| D{"Регистрированы обработчики команд / событий?"}
    D -->|"Да"| E["lazy_load=True + activate_on<br/>Активация при поступлении события / команды"]
    D -->|"Нет"| F["lazy_load=True<br/>Загрузка при первом обращении к атрибуту"]
    C --> G["Вызов on_load() при запуске"]
    E --> H["Регистрация stub → инстанцирование при срабатывании"]
    F --> I["Прокси LazyModule"]

Рекомендованные сценарии использования ленивой загрузки (lazy_load=True)

Рекомендованные сценарии отключения ленивой загрузки (lazy_load=False)

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

Примечания

  1. Если ваш модуль использует ленивую загрузку, и если другие модули никогда не вызывались внутри ErisPulse, ваш модуль никогда не будет инициализирован.
  2. Если ваш модуль содержит такие компоненты, как модули, слушающие события, или другие активно слушающие модули, у вас есть два варианта: объявить триггер activate_on (сохранить ленивую загрузку, автоматически активировать при поступлении события) или объявить, что он должен быть загружен немедленно (lazy_load=False), иначе это повлияет на нормальное функционирование вашего модуля.
  3. Мы не рекомендуем отключать ленивую загрузку, если только у вас нет особых потребностей, иначе это может привести к проблемам с зависимостями и событиями жизненного цикла.
  4. В командном словаре activate_on объявления, name должен совпадать с реальным именем команды, зарегистрированной в модуле on_load с помощью @command() — в противном случае, после активации модуля, команда-заполнитель будет отменена, и команда, объявленная не соответствующая реализации, не будет существовать.

Связанные документы