Почему пустой серверный вызов в управляемом приложении 1С работает медленнее, чем в обычном?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработчики, переходящие с обычных форм на управляемые, часто замечают странную особенность: «пустой» вызов серверной процедуры в управляемом приложении (УП) занимает значительно больше времени, чем в обычном приложении (ОП). Если в обычном приложении на локальном сервере этот процесс занимает около 1–2 мс, то в управляемом приложении время ожидания возрастает до 10–15 мс. На первый взгляд кажется, что это системная ошибка или неоптимальность, но на самом деле за этим стоят фундаментальные архитектурные различия платформ. Разберем подробно, почему так происходит и что именно делает платформа в эти миллисекунды.

Сравнительный анализ замеров производительности

Проанализируем результаты тестов, проведенных на локальных машинах, где влияние сетевых задержек минимизировано (localhost). При выполнении 1000 циклов вызова пустого метода из общего модуля мы увидим следующую картину:

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

Анализ работы платформы через Техножурнал

Чтобы понять, куда уходит время, проанализируем лог Техножурнала (ТЖ) для одного «пустого» вызова в управляемом приложении. Рассмотрим ключевые события, которые фиксирует платформа:


45:46.074000-0,VRSREQUEST,4,process=1cv8,Method=POST,URI='/e1cib/modules/call?id=urn%3Amodule%3Amd%3A...'
45:46.074002-1,SCALL,4,process=1cv8,IName=IVResourceRemoteConnection,MName=send...
45:46.074005-1,SCALL,4,process=1cv8,IName=ISeanceContextStorage,MName=getSeanceParameterSer...
45:46.077015-15,CALL,2,process=rphost,Context=ОбщийМодуль.Сервер.Модуль.Тест...

Разберем по шагам, что означают эти записи и почему они важны для понимания производительности:

  1. VRSREQUEST (Virtual Resource System): В управляемом приложении любой вызов инкапсулируется в протокол VRS. Платформа формирует виртуальный HTTP POST запрос. Даже если вы работаете по протоколу TCP, внутри него «заворачивается» полноценная структура с заголовками (Headers), URI ресурса и телом запроса. Это необходимо для унификации работы тонкого и веб-клиентов.
  2. ISeanceContextStorage и синхронизация параметров: События getSeanceParameterSer и seanceParametersCommit показывают, что при каждом вызове сервера платформа синхронизирует Параметры сеанса. Платформа должна убедиться, что состояние сеанса на клиенте и сервере идентично. В обычном приложении этот механизм работает более «лениво» или использует общую память, что экономит время.
  3. Проверка версий метаданных: В параметре URI мы видим идентификаторы версии модуля. Сервер обязан при каждом вызове проверить, не изменился ли код модуля, не была ли обновлена конфигурация и имеет ли пользователь права на этот вызов.
  4. Сериализация данных: Даже если вы не передаете параметры, платформа формирует XML/JSON структуру ответа и запроса, упаковывает её (используя алгоритмы zstd или lz4) и подготавливает среду исполнения на стороне rphost.

Влияние контекста формы

Выясним причину, почему директива &НаСервере работает значительно медленнее, чем &НаСервереБезКонтекста. В управляемом приложении реализована Stateless-архитектура (без сохранения состояния на сервере между вызовами в привычном понимании).

Когда мы используем &НаСервере:

В «тяжелых» формах время такого «путешествия» может составлять не 15 мс, а 200–500 мс, даже если процедура не содержит ни одной строки кода. Использование &НаСервереБезКонтекста исключает передачу данных формы, оставляя только системный оверхед протокола (те самые 5–10 мс).

Почему в обычном приложении быстрее?

Проанализируем ситуацию в обычном приложении. Толстый клиент в обычном режиме работает как Stateful-приложение. Он использует более низкоуровневые механизмы RPC (Remote Procedure Call) или прямой маршалинг объектов, если клиент и сервер находятся на одной машине.

В обычном приложении платформа «доверяет» состоянию сеанса и не выполняет такую жесткую проверку и синхронизацию параметров при каждом чихе, как это делает управляемый интерфейс, спроектированный для работы в нестабильных интернет-сетях. В ОП вызовы идут практически «напрямую» в память процесса, что и дает заветные 1–2 мс.

Как оптимизировать работу в управляемом приложении?

Выяснив, что задержка в 15 мс — это фундаментальное ограничение платформы, связанное с безопасностью, универсальностью и синхронизацией сеанса, мы должны изменить подходы к разработке:

  1. Минимизируем количество вызовов (Принцип «Один вызов — одна задача»): Если в обычном приложении мы могли позволить себе вызвать сервер 10 раз в цикле, то в УП это приведет к зависанию интерфейса на 150 мс. Рациональнее собрать все данные в одну структуру (Массив или Структура) и передать их на сервер за один вызов.
  2. Используем безконтекстные вызовы: Всегда, когда не требуется доступ к реквизитам формы, используйте &НаСервереБезКонтекста. Это сократит время вызова в 2–3 раза по сравнению с контекстным вызовом.
  3. Перенос логики на сервер: Старайтесь проектировать код так, чтобы клиент только инициировал процесс, а вся цепочка обработки данных происходила внутри одного серверного вызова, без промежуточных возвратов на клиент.
  4. Кэширование на клиенте: Если вам часто нужны данные с сервера, которые редко меняются, рассмотрите возможность использования ПовторноеИспользованиеЗначений с кэшированием на время сеанса или использование временных хранилищ.

Рассмотрим пример оптимизации кода. Вместо вызова в цикле:


// Плохая практика для УП
Для Каждого Строка Из ТаблицаТоваров Цикл
    Результат = СерверныйМодуль.ПроверитьОстаток(Строка.Номенклатура); // 100 итераций * 15 мс = 1.5 сек!
КонецЦикла;

Разберем правильный подход:


// Хорошая практика для УП
СписокНоменклатуры = ТаблицаТоваров.ВыгрузитьКолонку("Номенклатура");
СоответствиеОстатков = СерверныйМодуль.ПроверитьОстаткиСписком(СписокНоменклатуры); // 1 вызов * 15 мс = 0.015 сек!

Резюме: Разница в скорости серверных вызовов между ОП и УП — это не баг, а плата за возможность работы через Web, за безопасность данных и гарантированную целостность сеанса. Понимание механики работы VRSREQUEST и ISeanceContextStorage позволяет разработчику писать более производительный код, избегая лишних транзакций между клиентом и сервером.

← На главную