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

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

При разработке и сопровождении систем на базе 1С:Предприятие 8, работающих в режиме обычного приложения, программисты часто сталкиваются с неожиданными «просадками» производительности. Одной из самых коварных ситуаций является вызов серверной процедуры из модуля объекта документа в момент его проведения. Казалось бы, код выполняется на сервере, база данных — на сервере, почему же простая передача параметров занимает секунды? Давайте подробно разберем природу этого эффекта, проанализируем архитектурные особенности «Толстого клиента» и выясним, как оптимизировать такие вызовы.

Миф о режиме «Сервер-Сервер» в обычном приложении

Главное заблуждение, которое мы должны развеять в самом начале: в обычном приложении (на обычных формах) процедура ОбработкаПроведения далеко не всегда выполняется в серверном контексте. Если пользователь запускает проведение документа интерактивно из формы или списка, то в режиме обычного приложения процедура модуля объекта стартует в контексте Толстого клиента.

Это принципиальное отличие от управляемого приложения, где логика проведения жестко отделена от клиента. В обычном приложении, несмотря на то что данные читаются из SQL, программный код модуля объекта исполняется на компьютере пользователя. Следовательно, когда мы вызываем метод общего модуля с признаком Вызов сервера, платформа инициирует полноценный сетевой вызов (Remote Procedure Call, RPC). Рассмотрим подробнее, что происходит «под капотом» этого процесса.

Механизм сериализации и маршалинга тяжелых объектов

Проанализируем ситуацию, когда в качестве параметра серверной процедуры выступает РегистрНакопленияНаборЗаписей. Этот объект является крайне «тяжелым» для платформы 1С. Когда мы передаем его с клиента на сервер, происходит процесс маршалинга (упаковки):

  1. Подготовка данных: Платформа должна собрать все строки набора записей, их измерения, ресурсы и реквизиты.
  2. Сериализация: Все накопленные в памяти клиента данные преобразуются в бинарный поток или XML-подобный формат, пригодный для передачи по протоколу TCP/IP. Если в наборе тысячи строк, объем этого потока может достигать нескольких мегабайт.
  3. Передача по сети: Пакеты данных отправляются на сервер приложений 1С. Здесь на скорость напрямую влияет пропускная способность сети и задержки (latency).
  4. Десериализация: На стороне сервера платформа восстанавливает объект из байтового потока в оперативную память серверного процесса.

Разберем пример кода, который часто становится причиной тормозов:


// Модуль объекта документа
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    // Подготовка движений
    Движения.ОстаткиТоваров.Записывать = Истина;
    // ... заполнение движений ...
    
    // Вызов серверного модуля
    МодульПроведенияСервер.ВыполнитьСложныйРасчет(Движения.ОстаткиТоваров);
КонецПроцедуры

В данном примере, если в ОстаткиТоваров находится 5000 строк, каждый вызов будет сопровождаться огромными накладными расходами на копирование памяти.

Роль ключевого слова Знач в оптимизации вызовов

Выясним, почему отсутствие ключевого слова Знач (передача по значению) в описании параметров серверной процедуры удваивает время ожидания. В 1С по умолчанию параметры передаются «по ссылке» (точнее, с возможностью возврата значения). Это означает следующее:

Когда процедура на сервере завершает свою работу, платформа полагает, что объект мог измениться. Поэтому она выполняет обратную сериализацию набора записей с сервера и отправляет его обратно на клиент, чтобы обновить состояние объекта там.

Рассмотрим разницу в объявлении процедур:


// ВАРИАНТ 1: Медленно (двусторонняя передача данных)
Процедура РассчитатьДанные(НаборЗаписей) Экспорт
    // ... логика ...
КонецПроцедуры

// ВАРИАНТ 2: Быстрее (передача только в одну сторону)
Процедура РассчитатьДанные(Знач НаборЗаписей) Экспорт
    // ... логика ...
КонецПроцедуры

Использование Знач для тяжелых объектов при вызове сервера — это обязательное правило для программиста 1С, работающего с толстым клиентом.

Особенности Толстого клиента и синхронизация контекста

Посмотрим на ситуацию шире. Толстый клиент в обычном приложении — это «тяжеловесный» процесс. В отличие от тонкого клиента, он кэширует огромные объемы метаданных и поддерживает состояние глобального контекста. При каждом серверном вызове платформа выполняет проверку прав доступа, инициализацию параметров сеанса (если они не были созданы ранее) и синхронизацию состояния переменных.

В условиях распределенной сети или при работе через VPN накладные расходы на создание «туннеля» между клиентом и сервером для одного вызова могут составлять от 100 до 500 миллисекунд даже без учета передачи самих данных. Если вызовов несколько в цикле, время проведения документа возрастает экспоненциально.

Стратегии решения проблемы

Проанализировав причины, мы можем выработать несколько стратегий оптимизации, чтобы исключить просадки производительности.

1. Перенос всей логики на сторону сервера

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

Сравним подходы:


// Плохой подход: передаем мегабайты данных
МодульСервер.ОбработатьДвижения(Движения.ОстаткиТоваров);

// Хороший подход: передаем 16 байт (UUID ссылки)
МодульСервер.СформироватьИЗаписатьДвижения(ЭтотОбъект.Ссылка);

2. Использование программного проведения на сервере

Если нам нужно провести документ максимально быстро, стоит избегать интерактивного проведения. Если мы вызываем ДокументОбъект.Записать(РежимЗаписиДокумента.Проведение) в коде, который уже выполняется на сервере (например, в регламентном задании или в серверной обработке), то вся цепочка вызовов (включая ОбработкаПроведения) останется на сервере. В этом случае передачи данных по сети не будет, и наборы записей будут передаваться между процедурами мгновенно как указатели в памяти.

3. Минимизация данных в наборах

Если передача набора неизбежна, проанализируем, все ли строки нам нужны на сервере. Иногда достаточно передать только структуру с ключевыми параметрами или массив структур, который весит значительно меньше, чем полноценный объект РегистрНакопленияНаборЗаписей со всей его служебной информацией об изменениях строк.

Резюме для разработчика

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

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

Соблюдение этих архитектурных принципов позволит вашим решениям на базе 1С оставаться быстрыми и отзывчивыми даже при больших объемах данных в документах.

← На главную