При работе с крупными конфигурациями, такими как 1С:ERP Управление предприятием 2, программисты часто сталкиваются с проблемой резкого падения производительности при выполнении тривиальных действий. Одной из самых распространенных ситуаций является длительное (до нескольких минут) открытие динамического списка, например, «Документы продажи (все)». При анализе замера производительности выясняется, что система выполняет десятки тысяч раз одну и ту же функцию в общем модуле ОбщегоНазначения. Рассмотрим подробнее, почему это происходит и как исправить ситуацию.
Проанализируем ситуацию, когда при открытии списка документов фиксируется более 35 000 вызовов одной и той же функции за один сеанс работы со списком. Чаще всего речь идет о функциях поиска идентификаторов объектов метаданных (ИдентификаторОбъектаМетаданных) или методах получения представления объектов. Выясним причину такого аномального количества вызовов:
Самым эффективным способом борьбы с «лишними» вызовами без изменения логики типовой конфигурации является использование механизма повторного использования возвращаемых значений. Если функция при одинаковых входящих параметрах всегда возвращает один и тот же результат (как в случае с метаданными), нет смысла выполнять её код тысячи раз. Посмотрим, как реализовать это через расширение.
Шаг 1. Создание модуля в расширении. Создадим в расширении новый общий модуль, например, _прПовторноеИспользование. В свойствах модуля установим флаг «Повторное использование возвращаемых значений» в положение «На время сеанса».
Шаг 2. Перенос логики вызова. Вместо того чтобы править типовой код напрямую, мы создаем в этом модуле функцию-обертку, которая будет вызывать целевую тяжелую процедуру.
// В новом модуле расширения с включенным повторным использованием
Функция ПолучитьИдентификаторМетаданных(ИмяОбъекта) Экспорт
// Вызываем оригинальную тяжелую функцию из типового модуля
Возврат ОбщегоНазначения.ИдентификаторОбъектаМетаданных(ИмяОбъекта);
КонецФункции
Шаг 3. Внедрение через перехват. С помощью механизма &Вместо в расширении перехватываем вызов функции в исходном модуле ОбщегоНазначения и перенаправляем его в наш кэширующий модуль.
&Вместо("ИдентификаторОбъектаМетаданных")
Функция _прИдентификаторОбъектаМетаданных(Параметр)
// Система сначала заглянет в кэш нашего модуля
// Если для данного 'Параметр' результат уже есть, тело функции не выполнится
Возврат _прПовторноеИспользование.ПолучитьИдентификаторМетаданных(Параметр);
КонецФункции
Проанализируем ситуацию после внедрения: теперь при 37 000 обращений реальный код поиска по метаданным выполнится ровно столько раз, сколько уникальных типов объектов встретилось в списке (обычно не более пары десятков). Остальные 36 980 вызовов вернут значение мгновенно из оперативной памяти.
Важно понять, почему у одного пользователя может быть 150 вызовов, а у другого — 36 000. Рассмотрим факторы, влияющие на это:
Чтобы точно определить, откуда идет вызов, не нужно просматривать стек вызовов 36 000 раз вручную. Используйте следующие приемы:
Таким образом, решение проблемы кроется в сочетании грамотной настройки прав (минимизация RLS там, где это возможно) и технического кэширования повторяющихся вызовов через расширение. Это позволяет ускорить работу интерфейса в десятки раз без потери функциональности системы 1С:ERP.