Перейти к основному содержимому

Управление потоком выполнения 1С

Разработчику Архитектору

Сначала: Циклы в коде — общая идея повторений, виды циклов и типичные ошибки без привязки к синтаксису языка.


Управление потоком выполнения 1С

Play ITЗагрузка интерактивного демо…


Основные концепции управления потоком

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

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

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

ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
ИмяПользователя = ТекущийПользователь.Имя;

ЭтоВебКлиент = ОбщегоНазначенияКлиент.ЭтоВебКлиент();
ЭтоТонкийКлиент = ОбщегоНазначенияКлиент.ЭтоТонкийКлиент();

Сообщить("Пользователь: " + ИмяПользователя + ", клиент: " + ?(ЭтоВебКлиент, "веб", ?(ЭтоТонкийКлиент, "тонкий", "толстый")));

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

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

НачатьТранзакцию();
Попытка
Док = Документы.ПоступлениеТоваров.СоздатьДокумент();
Док.Дата = ТекущаяДата();
Док.Организация = Справочники.Организации.НайтиПоНаименованию("ООО Ромашка");
Док.Записать(РежимЗаписиДокумента.Проведение);

// ещё какие-то изменения...

ЗафиксироватьТранзакцию();
Сообщить("Транзакция успешно завершена");
Исключение
ОтменитьТранзакцию();
ВызватьИсключение "Ошибка в транзакции: " + ОписаниеОшибки();
КонецПопытки;

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

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


Синхронное выполнение кода

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

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

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

Процедура ОбновитьОстатки(Склад, СписокНоменклатуры)
Для Каждого Номенклатура Из СписокНоменклатуры Цикл
// логика пересчёта остатков для Номенклатура на Склад
Сообщить("Пересчёт остатков: " + Номенклатура + " на складе " + Склад);
КонецЦикла;
КонецПроцедуры

Функция — блок кода, выполняющий вычисления и возвращающий результат. Функция может использоваться в выражениях, присваиваниях и условиях. Результат функции сохраняется в переменной или используется непосредственно в коде.

Функция РассчитатьСуммуСоСкидкой(Сумма, ПроцентСкидки)
Возврат Сумма * (1 - ПроцентСкидки / 100);
КонецФункции

Вызов по имени — механизм обращения к процедуре или функции через ее идентификатор. Платформа ищет объявление объекта в области видимости текущего модуля, затем в стандартных модулях, и наконец в глобальных объектах. Если объект не найден, возникает ошибка компиляции или выполнения.

ОбновитьОстатки(СкладСсылка, МассивНоменклатуры);
ИтоговаяСумма = РассчитатьСуммуСоСкидкой(1000, 15); // 850

ИмяМетода = "РассчитатьСуммуСоСкидкой";
Код = ИмяМетода + "(1000, 15)";
Результат = Выполнить(Код);

Выполнить() опасен при использовании непроверенных данных (риск внедрения кода). В типовых решениях стараются избегать его в пользовательском вводе. Альтернатива — справочник/структура «имя → процедура» и явный диспетчер:

Процедура ВызватьПоИмени(Имя, Параметры)
Если Имя = "ОбновитьОстатки" Тогда
ОбновитьОстатки(Параметры.Склад, Параметры.Номенклатура);
ИначеЕсли Имя = "ПересчитатьКурсы" Тогда
ПересчитатьКурсы(Параметры.Дата);
КонецЕсли;
КонецПроцедуры

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

Процедура ОбойтиИерархию(Родитель, Уровень)
Элемент = Справочники.Номенклатура.Выбрать(,,ОтборПоРодителю(Родитель));
Пока Элемент.Следующий() Цикл
Сообщить(СтрПовтор(" ", Уровень) + Элемент.Наименование);
ОбойтиИерархию(Элемент.Ссылка, Уровень + 1); // рекурсивный вызов
КонецЦикла;
КонецПроцедуры

ОбойтиИерархию(Справочники.Номенклатура.ПустаяСсылка(), 0);
// Пример рекурсивной функции для вычисления факториала
Функция Факториал(Число) Экспорт

Если Число <= 1 Тогда
Возврат 1;
КонецЕсли;

Возврат Число * Факториал(Число - 1);

КонецФункции

Результат = Факториал(5); // Вернет 120

Интерактивное демо — пошаговый цикл на примере JavaScript (for, while). В 1С — Пока, Для, Цикл; демо на JavaScript иллюстрирует ту же логику итераций. Обобщённо: циклы в коде.

Play ITЗагрузка интерактивного демо…

Циклы обеспечивают повторение блока кода несколько раз. Основные конструкции — Пока, Для … По, Для Каждого … Из и бесконечный Цикл с Прервать / Продолжить.

Для Счётчик = 1 По 10 Цикл
Сообщить("Итерация: " + Счётчик);
КонецЦикла;

Счётчик = 1;
Пока Счётчик <= 10 Цикл
Сообщить("Пока: " + Счётчик);
Счётчик = Счётчик + 1;
КонецЦикла;

Массив = Новый Массив;
Массив.Добавить(10); Массив.Добавить(20); Массив.Добавить(30);

Для Каждого Значение Из Массив Цикл
Сообщить("Значение: " + Значение);
КонецЦикла;

Запрос = Новый Запрос("ВЫБРАТЬ Номенклатура.Ссылка ИЗ Справочник.Номенклатура КАК Номенклатура");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Сообщить(Выборка.Ссылка);
КонецЦикла;

Цикл Пока выполняется, пока условие истинно. Условие проверяется перед каждой итерацией. Если условие ложно сразу, цикл не выполнится ни разу.

// Цикл Пока
Значение = 1;
Пока Значение <= 10 Цикл
Сообщить("Значение: " + Значение);
Значение = Значение + 1;
КонецЦикла;

Цикл Для перебирает элементы коллекции или выполняет заданное количество раз. Переменная цикла принимает значения от начального до конечного значения с определенным шагом.

// Цикл Для
Для Счетчик = 1 По 10 Цикл
Сообщить("Итерация: " + Счетчик);
КонецЦикла;

Операторы перехода позволяют изменять обычный порядок выполнения кода. Операторы Прервать, Перейти, Возврат и ВызватьИсключение предоставляют гибкость управления потоком. В языке 1С нет оператора goto. Вместо него используют:

  • досрочный выход из цикла: Прервать;
  • переход к следующей итерации: Продолжить;
  • выход из процедуры/функции: Возврат.
Для Счётчик = 1 По 100 Цикл
Если Счётчик = 50 Тогда
Прервать; // аналог «перейти дальше после цикла»
КонецЕсли;
Если Счётчик % 2 = 0 Тогда
Продолжить; // пропустить чётные
КонецЕсли;
Сообщить("Нечётное: " + Счётчик);
КонецЦикла;

Процедура Проверка(Значение)
Если Значение < 0 Тогда
Возврат; // выход из процедуры
КонецЕсли;
// дальнейшая логика
КонецПроцедуры;

Прервать останавливает выполнение текущего цикла и передает управление следующей инструкции после цикла.

Для Счетчик = 1 По 100 Цикл
Если Счетчик > 10 Тогда
Прервать;
КонецЕсли;
Сообщить(Счетчик);
КонецЦикла; // Выведет числа от 1 до 10

Перейти (переход к метке) в современном коде почти не используют — предпочтительны циклы и ранний Возврат.

Возврат завершает выполнение процедуры или функции и возвращает управление месту вызова. В функции возврат должен содержать значение результата.

Функция НайтиМаксимум(Массив) Экспорт
Макс = Массив[1];
Для Индекс = 2 По Количество(Массив) Цикл
Если Массив[Индекс] > Макс Тогда
Макс = Массив[Индекс];
КонецЕсли;
КонецЦикла;
Возврат Макс;
КонецФункции

Типовые сценарии в 1С

  • Проведение документа: проверка условий -> запись движений -> фиксация транзакции.
  • Обработка формы: пользовательское событие -> валидация ввода -> вызов серверной процедуры.
  • Фоновая задача: запуск по расписанию -> пакетная обработка -> логирование результата.

Если этапы перемешаны (например, тяжелые вычисления в модуле формы), интерфейс начинает "подвисать", а ошибки становятся труднее для диагностики.

Для автоматизации периодических задач в среде исполнения предусмотрены:

  • Регламентные задания — задачи по расписанию (закрытие месяца, пересчёт итогов, обмен данными).
  • Фоновые задания — длительные операции, которые можно запускать асинхронно и отслеживать их статус.
  • Задания могут выполняться на конкретных серверах кластера, что позволяет выносить тяжёлые задачи с основных узлов.

Куда идти дальше