Как реализовать паузу или задержку выполнения в цикле 1С:Предприятие?

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

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

1. Современный и рекомендуемый метод: ПриостановитьРаботающийПоток

Начиная с версии платформы 8.3.18, разработчики получили штатный и наиболее правильный инструмент для решения этой задачи. Метод ПриостановитьРаботающийПоток() позволяет остановить выполнение текущего потока кода на заданное количество секунд. Проанализируем его преимущества: он работает кроссплатформенно (Windows/Linux), доступен как на клиенте, так и на сервере, и, что самое важное, не нагружает процессор бесполезными вычислениями.

Рассмотрим пример использования данного метода в цикле:


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

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

2. Использование системных команд Windows (COM-объекты)

Если разработка ведется под управлением ОС Windows, мы можем воспользоваться возможностями операционной системы. Одним из классических способов является использование объекта WScript.Shell. Разберем по шагам, как это работает: мы создаем COM-объект, который имеет встроенный метод Sleep, принимающий время задержки в миллисекундах.


// 5000 миллисекунд = 5 секунд
Пауза = Новый COMОбъект("WScript.Shell");
Для каждого СтрТЧ Из Объект.Товары Цикл
    Пауза.Run("ping -n 1 -w 5000 127.0.0.1", 0, Истина);
    // Или более простой вариант через sleep в скрипте, но Run с ping часто надежнее
    ВыполнитьЗаполнениеТЧ(СтрТЧ);
КонецЦикла;

Однако стоит помнить, что создание COM-объекта на каждой итерации — это ресурсозатратная операция. Правильнее будет инициализировать объект один раз перед циклом. Также отметим, что данный метод не будет работать в среде Linux или в облачных сервисах, где запрещен запуск внешних компонентов.

3. Команда системы ping

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


Для каждого СтрТЧ Из Объект.Товары Цикл
    КомандаСистемы("ping -n 1 -w 5000 127.0.0.1");
    ВыполнитьЗаполнениеТЧ(СтрТЧ);
КонецЦикла;

Важный нюанс: использование КомандаСистемы может приводить к появлению "черных окон" консоли, что пугает пользователей. Для скрытого выполнения лучше использовать метод ЗапуститьПриложение с соответствующими параметрами видимости окна.

4. Метод «Пустого цикла» через ТекущаяДата

Иногда разработчики прибегают к самому простому, на первый взгляд, решению — циклу, который сравнивает текущее время с моментом начала паузы. Посмотрим на пример реализации:


Процедура Пауза(Секунд)
    ДатаНачала = ТекущаяДата();
    Пока ТекущаяДата() - ДатаНачала < Секунд Цикл
        // Процессор работает на 100%, выполняя это сравнение
    КонецЦикла;
КонецПроцедуры

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

5. Асинхронный подход: ПодключитьОбработчикОжидания

Если задача стоит на стороне клиента (в управляемом приложении) и нам важно, чтобы интерфейс программы не "зависал" во время ожидания, следует использовать ПодключитьОбработчикОжидания. Этот метод не делает паузу внутри кода в привычном понимании, а велит платформе вызвать определенную процедуру через заданный интервал.

Разберем, как перестроить алгоритм перебора таблицы значений на асинхронный лад:


&НаКлиенте
Перем ТекущийИндекс;

&НаКлиенте
Процедура НачатьОбработкуТЧ()
    ТекущийИндекс = 0;
    // Запускаем обработку первой строки через 5 секунд
    ПодключитьОбработчикОжидания("ОбработатьСледующуюСтроку", 5, Истина);
КонецПроцедуры

&НаКлиенте
Процедура ОбработатьСледующуюСтроку()
    Если ТекущийИндекс < Объект.Товары.Количество() Тогда
        СтрТЧ = Объект.Товары[ТекущийИндекс];
        ВыполнитьЗаполнениеТЧ(СтрТЧ);
        
        ТекущийИндекс = ТекущийИндекс + 1;
        // Рекурсивно подключаем обработчик для следующей строки
        ПодключитьОбработчикОжидания("ОбработатьСледующуюСтроку", 5, Истина);
    КонецЕсли;
КонецПроцедуры

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

6. Хакерский способ: HTTP-запрос с таймаутом

Для старых версий платформы (ниже 8.3.18) на стороне сервера существует способ сделать паузу, не нагружая процессор. Мы можем инициировать HTTP-запрос к несуществующему IP-адресу с заданным таймаутом ожидания.


Процедура ПаузаНаСервере(Секунды)
    НТТР = Новый HTTPСоединение("127.0.0.2", , , , , Секунды);
    Попытка
        НТТР.Получить(Новый HTTPЗапрос("/"));
    Исключение
        // Платформа подождет указанное количество секунд и вылетит по таймауту
    КонецПопытки;
КонецПроцедуры

Этот метод изящнее пустого цикла, так как ожидание ответа от сокета не нагружает CPU, однако он выглядит "костыльным" и может логировать ошибки сетевых соединений в системных журналах.

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

Подводя итог, выделим лучшие практики:

  1. Если у вас современная платформа (8.3.18+) — используйте ПриостановитьРаботающийПоток().
  2. Если нужно выполнять действия на клиенте без блокировки интерфейса — используйте ПодключитьОбработчикОжидания().
  3. Если вы работаете на старой платформе в Windows — используйте WScript.Shell.
  4. Никогда не используйте пустые циклы с ТекущаяДата() на сервере.

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

← На главную