Как реализовать паузу в 1С без нагрузки на процессор

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

При разработке сложных систем на платформе 1С:Предприятие часто возникает необходимость приостановить выполнение программного кода. Это особенно актуально для фоновых заданий, которые работают в многопоточном режиме, взаимодействуют с внешними API, ожидают освобождения ресурсов или обрабатывают очереди сообщений. Использование классического пустого цикла для организации паузы приводит к стопроцентной загрузке ядра процессора, что при наличии 100 и более одновременно работающих фоновых заданий может полностью парализовать работу сервера. Разберем, как сделать паузу «цивилизованными» средствами платформы, не нагружая серверное оборудование.

Причина проблемы: Активное vs Пассивное ожидание

Проанализируем, почему стандартные циклы или некоторые методы 1С не подходят для массовых фоновых процессов. Когда мы используем конструкцию типа Пока ТекущаяДата() < ДатаОкончания Цикл, процессор непрерывно выполняет операции сравнения, не переключаясь на другие задачи. Это называется активным ожиданием. Наша задача — перевести поток выполнения в состояние сна (пассивное ожидание), чтобы операционная система могла отдать ресурсы процессора другим полезным процессам.

Решение 1: Использование метода ОжидатьЗавершения() фонового задания

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

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


Процедура ВыполнитьПаузу(Секунд) Экспорт
    
    // Получаем текущее фоновое задание, если код выполняется в фоне
    ТекущийСеанс = ПолучитьТекущийСеансИнформационнойБазы();
    ФоновоеЗадание = ТекущийСеанс.ПолучитьФоновоеЗадание();
    
    // Если мы уже в фоновом задании, нам нужно создать вспомогательное
    // которое просто завершится сразу, а мы будем ждать его завершения
    Параметры = Новый Массив;
    Параметры.Добавить(Секунд);
    
    // В качестве выполняемого метода можно указать любую пустую процедуру
    // Например, из общего модуля ОбщегоНазначения
    Попытка
        НовоеЗадание = ФоновыеЗадания.Выполнить("ОбщегоНазначения.ПустаяПроцедура", Параметры);
        // Самый важный момент: ожидание с таймаутом
        НовоеЗадание.ОжидатьЗавершения(Секунд);
    Исключение
        // Исключение возникнет по истечении таймаута, что нам и нужно
        Возврат;
    КонецПопытки;
    
КонецПроцедуры

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

Решение 2: Делегирование паузы серверу СУБД (SQL Sleep)

Проанализируем ситуацию, когда нам нужно минимизировать нагрузку именно на сервер приложений 1С. Мы можем попросить сервер баз данных «заснуть» на определенное время. Это один из самых эффективных способов, так как СУБД гораздо лучше управляет потоками ожидания.

Для PostgreSQL мы можем использовать функцию pg_sleep. Посмотрим на пример кода через механизм внешних источников данных или прямое ADO-соединение:


// Пример для PostgreSQL
Запрос = Новый Запрос("ВЫБРАТЬ pg_sleep(5)"); // Пауза 5 секунд
Запрос.Выполнить();

Для MS SQL Server используется команда WAITFOR DELAY. Реализация через COM-объект (если это допустимо на сервере) или через выполнение запроса к базе:


// Пример логики для MS SQL через ADO
Connection = Новый COMОбъект("ADODB.Connection");
Connection.Open(СтрокаСоединения);
Connection.Execute("WAITFOR DELAY '00:00:05'"); // Пауза 5 секунд
Connection.Close();

Этот метод считается «чистым», так как поток 1С просто ждет ответа от SQL-сервера, находясь в состоянии ожидания сетевого ввода-вывода.

Решение 3: Системные вызовы через команду ping и sleep

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

Рассмотрим правильный пример использования ping для Windows, который создает паузу за счет ожидания ответа от несуществующего или локального адреса:


Процедура ПаузаЧерезКомандуСистемы(Секунд)
    Команда = СтрШаблон("ping -n 1 -w %1 127.255.255.255", Секунд * 1000);
    ЗапуститьПриложение(Команда, , Истина); // Истина - ждать завершения
КонецПроцедуры

Если ваш сервер работает на ОС Linux, лучше использовать прямую команду sleep, которая работает гораздо точнее и потребляет меньше ресурсов:


// Только для Linux-серверов
Команда = СтрШаблон("sleep %1", Секунд);
ЗапуститьПриложение(Команда, , Истина);

Решение 4: Механизм блокировок (Хак для продвинутых)

Существует специфический способ реализации паузы через менеджер блокировок 1С. Посмотрим на логику: мы пытаемся установить блокировку на ресурс, который заведомо занят другим сеансом, и указываем таймаут ожидания этой блокировки.

  1. Создаем вспомогательный регистр сведений БлокировкиПаузы.
  2. Сеанс-«держатель» устанавливает эксклюзивную блокировку на запись в этом регистре.
  3. Фоновое задание пытается заблокировать ту же запись с таймаутом в N секунд.
  4. Менеджер блокировок платформы 1С ставит фоновое задание в очередь. По истечении таймаута задание получит исключение и продолжит работу.

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

Итоги и рекомендации

Подведем итог нашему анализу. Выбор метода зависит от архитектуры вашего решения:

Главное правило: никогда не используйте пустые циклы (Пока... Цикл) для реализации пауз на сервере 1С. Это ведет к деградации производительности всей системы.

← На главную