Мы с вами часто сталкиваемся с ситуацией, когда наша конфигурация 1С начинает "тормозить", а пользователи жалуются на медленную работу. Одной из частых причин такого поведения является слишком большое количество запросов к серверу. Это происходит, когда клиентское приложение слишком часто обращается к серверу для получения или отправки данных, особенно в циклах или при выполнении сложных операций. Давайте вместе разберем, как мы можем оптимизировать взаимодействие клиент-сервер и сделать нашу систему более отзывчивой и производительной.
Основной принцип, которым мы будем руководствоваться, — это минимизация количества серверных вызовов и объема передаваемых данных. Мы хотим, чтобы каждое действие пользователя или программный алгоритм выполнялся с наименьшим числом обращений к серверу, а если обращения неизбежны, то они должны быть максимально эффективными.
Прежде чем перейти к конкретным механизмам, рассмотрим несколько общих правил, которые помогут нам снизить нагрузку на сервер:
Представьте ситуацию: нам нужно периодически проверять что-то на сервере или выполнять небольшие порции работы, не блокируя при этом пользовательский интерфейс. Для таких задач на стороне клиента мы можем использовать механизм ПодключитьОбработчикОжидания.
Что такое Обработчик Ожидания?
Это специальный механизм платформы 1С, который позволяет нам указать процедуру для выполнения в "состоянии покоя" системы, то есть когда программа не выполняет никаких активных действий и ждет ввода пользователя. Процедура будет запускаться через заданный интервал времени.
Как мы можем его использовать для снижения нагрузки?
Вместо того чтобы делать множество запросов к серверу подряд в одном цикле, мы можем разбить эту работу на мелкие порции и выполнять их по одной с небольшой задержкой. Это особенно полезно при взаимодействии с внешними системами, которые могут ограничивать частоту запросов (например, 1 запрос в секунду). Мы с вами можем реализовать это следующим образом:
Рассмотрим подробнее пример с динамической задержкой:
Иногда внешние системы могут быть перегружены, и наши запросы могут отваливаться. В этом случае мы можем адаптивно увеличивать интервал ожидания. Давайте посмотрим на пример такого алгоритма:
// Переменные формы
Перем мИнтервалОжидания;
Перем мБазовыйИнтервалОжидания;
Перем мСчетчикПопыток;
&НаКлиенте
Процедура ПриОткрытии(Отказ)
мБазовыйИнтервалОжидания = 3; // Базовый интервал в секундах
мИнтервалОжидания = мБазовыйИнтервалОжидания;
мСчетчикПопыток = 0;
ПодключитьОбработчикОжидания("ОбработатьПорциюДанныхНаСервере", мИнтервалОжидания);
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьПорциюДанныхНаСервере()
// Отключаем текущий обработчик, чтобы избежать повторных срабатываний
ОтключитьОбработчикОжидания("ОбработатьПорциюДанныхНаСервере");
Попытка
// Выполняем вызов сервера для обработки очередной порции
// Например, получаем 500 записей
Результат = ВызватьСерверДляОбработкиПорции();
Если Результат.Успех Тогда
// Если успешно, сбрасываем интервал ожидания до базового
мИнтервалОжидания = мБазовыйИнтервалОжидания;
мСчетчикПопыток = 0;
// Здесь обрабатываем полученные данные
// ...
Если Результат.ВсеДанныеОбработаны Тогда
// Если все данные обработаны, больше не подключаем обработчик
Сообщить("Все данные успешно обработаны.");
Иначе
// Если есть еще данные, подключаем обработчик снова с базовым интервалом
ПодключитьОбработчикОжидания("ОбработатьПорциюДанныхНаСервере", мИнтервалОжидания);
КонецЕсли;
Иначе
// Если произошла ошибка на сервере, увеличиваем интервал ожидания
мСчетчикПопыток = мСчетчикПопыток + 1;
мИнтервалОжидания = мИнтервалОжидания + 2 * мСчетчикПопыток; // Увеличиваем на 2, 4, 6... секунды
Сообщить("Ошибка при обработке порции данных. Повторная попытка через " + мИнтервалОжидания + " секунд.");
ПодключитьОбработчикОжидания("ОбработатьПорциюДанныхНаСервере", мИнтервалОжидания);
КонецЕсли;
Исключение
// Обработка исключений на клиенте (например, потеря связи)
мСчетчикПопыток = мСчетчикПопыток + 1;
мИнтервалОжидания = мИнтервалОжидания + 2 * мСчетчикПопыток;
Сообщить("Произошла ошибка связи. Повторная попытка через " + мИнтервалОжидания + " секунд. " + ОписаниеОшибки());
ПодключитьОбрабочикОжидания("ОбработатьПорциюДанныхНаСервере", мИнтервалОжидания);
КонецПопытки;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ВызватьСерверДляОбработкиПорции()
// Здесь мы с вами получаем или обрабатываем очередную порцию данных.
// Например, выбираем 500 записей из базы данных.
// ...
Результат = Новый Структура;
Результат.Вставить("Успех", Истина); // Или Ложь, если произошла ошибка
Результат.Вставить("ВсеДанныеОбработаны", Ложь); // Или Истина, если обработка завершена
Возврат Результат;
КонецФункции
Важные моменты при работе с Обработчиком Ожидания:
Для более длительных и ресурсоемких операций, которые должны выполняться на сервере и не зависеть от активности пользователя на клиенте, мы с вами используем механизм Регламентных и Фоновых заданий. Это идеальное решение, когда нам нужно обрабатывать большие объемы данных, выполнять синхронизации или генерировать отчеты по расписанию.
Что такое Регламентные и Фоновые задания?
Как мы можем их использовать для снижения нагрузки?
Представьте, что нам нужно регулярно получать большие объемы данных (например, из ФГИС "Зерно") или обрабатывать множество документов. Вместо того чтобы клиентский компьютер запрашивал эти данные или запускал обработку, мы можем:
Преимущества этого подхода:
Пример использования:
Мы с вами можем создать экспортную процедуру в общем модуле, которая будет вызываться регламентным заданием:
// Общий модуль, например, "РаботаСДаннымиСервер" с галочкой "Сервер" и "ВызовСервера"
// и "Глобальный" (если это необходимо)
Процедура ОбработатьОчереднуюПорциюДанных() Экспорт
// Здесь мы с вами должны определить, какую порцию данных нужно обрабатывать
// и сохранить состояние между вызовами.
// Это может быть регистр сведений, где хранится последний обработанный ID,
// или специальный объект для управления фоновой очередью.
// Пример: получаем 500 необработанных записей
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 500
| ДанныеДляОбработки.Ссылка
|ИЗ
| Документ.МойДокумент КАК ДанныеДляОбработки
|ГДЕ
| НЕ ДанныеДляОбработки.Обработан"; // Предположим, есть флаг "Обработан"
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Обрабатываем текущую запись
Объект = Выборка.Ссылка.ПолучитьОбъект();
// ... выполняем нужные действия с объектом ...
Объект.Обработан = Истина;
Объект.Записать();
КонецЦикла;
// Если все данные обработаны, регламентное задание можно временно отключить
// или оно будет просто запускаться вхолостую до появления новых данных.
КонецПроцедуры
Далее мы регистрируем это задание в конфигурации или через программный интерфейс, указывая расписание запуска. Например, каждые 5 секунд.
Важный совет: Если функциональность, за которую отвечает регламентное задание, временно не нужна или отключена в программе, мы должны отключать и само задание, чтобы не расходовать вычислительные ресурсы сервера 1С:Предприятие.
С платформы 1С:Предприятие версии 8.3.18 у нас появилась мощная возможность для написания неблокирующего кода на клиенте — асинхронное программирование с использованием ключевых слов Асинх и Ждать (Async / Await).
Что это такое?
Асинхронное программирование позволяет нам выполнять длительные операции, не блокируя при этом основной поток выполнения программы. Это означает, что пользовательский интерфейс остается отзывчивым, пока данные загружаются или сложные расчеты выполняются на сервере или во внешней системе. Код при этом выглядит последовательным, что упрощает его понимание.
Когда это особенно полезно?
ПодключитьОбработчикОжидания с его ограничениями.Пример использования:
Предположим, нам нужно получить большой объем данных с сервера по кнопке, но не блокировать форму:
&НаКлиенте
Процедура ПолучитьДанныеАсинхронно(Команда)
Сообщить("Начинаем получать данные... Интерфейс не заблокирован.");
// Вызываем асинхронную серверную процедуру
Ждать ВызватьСерверДляПолученияБольшихДанныхАсинх();
Сообщить("Данные получены и обработаны!");
КонецПроцедуры
&НаСервереАсинх
Функция ВызватьСерверДляПолученияБольшихДанныхАсинх()
// Эта процедура выполняется на сервере асинхронно.
// Она может содержать длительные операции, например,
// выборку большого объема данных или обращение к внешнему API.
// Имитация длительной операции
Пауза(10); // Пауза на 10 секунд
// ... логика получения и обработки данных ...
// Возвращаем результат, если необходимо
Возврат "Успешно";
КонецФункции
Обратите внимание на ключевые слова &НаСервереАсинх для серверной процедуры и Ждать для вызова этой процедуры на клиенте. Это позволяет нам выполнять код на сервере, не ожидая его завершения в клиентском потоке.
Помимо рассмотренных механизмов, мы с вами можем применить и другие техники для снижения количества запросов и повышения производительности:
ВыбратьПоСсылкам(). Для массовой обработки объектов по набору ссылок в платформе 1С планируется реализовать метод ВыбратьПоСсылкам() у менеджеров объектов. Это позволит нам получить выборку данных сразу многих объектов за одно обращение к базе данных, вместо многократных ПолучитьОбъект().ВЫБРАТЬ *. Всегда явно указывайте поля, которые вам нужны. Выбор всех полей, особенно в больших таблицах, увеличивает объем передаваемых данных.ПОМЕСТИТЬ).Опыт работы с такими системами, как ФГИС "Зерно", показывает, что контролируемое взаимодействие является ключом к успеху. Мы должны:
ОбработчикОжидания. Это помогает избежать перегрузки внешнего сервиса и блокировки наших запросов.Мы с вами разобрали различные подходы к решению проблемы избыточных запросов к серверу в 1С. Выбор конкретного метода зависит от специфики задачи: для клиентских фоновых операций с небольшой задержкой подойдет ОбработчикОжидания; для длительных серверных задач, выполняющихся по расписанию, — Регламентные и Фоновые задания; а для современного неблокирующего клиент-серверного взаимодействия — Асинхронное программирование. Комбинируя эти подходы и следуя общим принципам оптимизации, мы сможем значительно улучшить производительность и отзывчивость наших систем 1С.