Фоновые задания 1С позволяют превратить длинный последовательный цикл в несколько параллельных потоков: массив объектов делится на порции, на каждую порцию запускается ФоновыеЗадания.Выполнить() с экспортной процедурой общего модуля, а затем код ждёт завершения всех заданий и собирает результаты. На клиент-серверной базе это заметно сокращает время обработки, если объекты не конкурируют за одни и те же данные.
Важная оговорка: сам запуск возвращает управление мгновенно. «Обработка за секунду вместо пятнадцати» — это только время запуска; работа продолжается в фоне. Ниже — как сделать параллельную обработку честно: с ожиданием, сбором результатов и контролем ошибок.
Исходная задача
Типичный последовательный код:
&НаСервере
Процедура ОбработатьВсеОбъекты()
Ссылки = ПолучитьОбъектыДляОбработки();
Для Каждого Ссылка Из Ссылки Цикл
ОбработатьОбъект(Ссылка);
КонецЦикла;
КонецПроцедурыЕсли ОбработатьОбъект тратит заметное время (перезаполнение, перепроведение, обращение к внешнему сервису), а объекты независимы, их можно обрабатывать параллельно.

Шаг 1. Делим массив на порции
// Делит массив на заданное число порций примерно одинакового размера.
Функция РазделитьНаПорции(Элементы, ЧислоПорций) Экспорт
ЧислоПорций = Макс(1, Мин(ЧислоПорций, Элементы.Количество()));
Порции = Новый Массив;
Для Номер = 1 По ЧислоПорций Цикл
Порции.Добавить(Новый Массив);
КонецЦикла;
Для Индекс = 0 По Элементы.ВГраница() Цикл
Порции[Индекс % ЧислоПорций].Добавить(Элементы[Индекс]);
КонецЦикла;
Возврат Порции;
КонецФункцииРаскладка «по кругу» даёт порции одинакового размера без отдельной обработки остатка — в отличие от деления Цел(Количество / N), где хвост часто попадает в лишнюю маленькую порцию.
Шаг 2. Метод, который выполняется в фоне
Метод для фонового задания должен быть экспортной процедурой серверного общего модуля. Результат возвращаем через временное хранилище:
// Общий модуль ОбработкаОбъектовФоновая (серверный).
// Обрабатывает порцию объектов, итог кладет по адресу во временном хранилище.
Процедура ОбработатьПорцию(Ссылки, АдресРезультата) Экспорт
Итог = Новый Структура("Обработано, Ошибки", 0, Новый Массив);
Для Каждого Ссылка Из Ссылки Цикл
Попытка
ОбработатьОбъект(Ссылка);
Итог.Обработано = Итог.Обработано + 1;
Исключение
Итог.Ошибки.Добавить(СтрШаблон("%1: %2", Ссылка,
КраткоеПредставлениеОшибки(ИнформацияОбОшибке())));
КонецПопытки;
КонецЦикла;
ПоместитьВоВременноеХранилище(Итог, АдресРезультата);
КонецПроцедурыОшибку по одному объекту ловим внутри цикла: иначе одно исключение остановит всю порцию.
Шаг 3. Запуск и ожидание
// Запускает обработку порциями в фоновых заданиях и дожидается завершения.
Функция ОбработатьПараллельно(Ссылки, ЧислоПотоков = 4) Экспорт
Порции = РазделитьНаПорции(Ссылки, ЧислоПотоков);
Запуски = Новый Массив;
Для Номер = 0 По Порции.ВГраница() Цикл
АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор);
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(Порции[Номер]);
ПараметрыЗадания.Добавить(АдресРезультата);
Задание = ФоновыеЗадания.Выполнить("ОбработкаОбъектовФоновая.ОбработатьПорцию",
ПараметрыЗадания, , СтрШаблон("Обработка объектов, порция %1", Номер + 1));
Запуски.Добавить(Новый Структура("Задание, Адрес", Задание, АдресРезультата));
КонецЦикла;
Сводка = Новый Структура("Обработано, Ошибки", 0, Новый Массив);
Для Каждого Запуск Из Запуски Цикл
Задание = Запуск.Задание.ОжидатьЗавершенияВыполнения();
Если Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда
Сводка.Ошибки.Добавить(ПодробноеПредставлениеОшибки(Задание.ИнформацияОбОшибке));
Продолжить;
КонецЕсли;
Итог = ПолучитьИзВременногоХранилища(Запуск.Адрес);
Если Итог <> Неопределено Тогда
Сводка.Обработано = Сводка.Обработано + Итог.Обработано;
Для Каждого ТекстОшибки Из Итог.Ошибки Цикл
Сводка.Ошибки.Добавить(ТекстОшибки);
КонецЦикла;
КонецЕсли;
КонецЦикла;
Возврат Сводка;
КонецФункцииЗадания стартуют все сразу, а ожидаем мы их по очереди — это не замедляет обработку: пока ждём первое, остальные тоже работают. Метод ОжидатьЗавершенияВыполнения() возвращает актуальное состояние задания, поэтому проверяем Состояние у возвращённого значения.
Третий параметр Выполнить — ключ задания. Если указать осмысленный ключ, платформа не даст запустить второе активное задание с тем же ключом. Это полезно для регламентных сценариев, чтобы обработка не стартовала дважды.
Когда ждать на сервере нельзя
Если запуск идёт из формы по кнопке, ожидание в серверном вызове держит клиента: пользователь видит «зависшее» окно. Для интерактивных сценариев лучше:
- запустить задания и сразу вернуться на клиент;
- проверять состояние обработчиком ожидания формы;
- либо использовать механизм длительных операций БСП, который даёт окно ожидания и многопоточность из коробки.
Ожидание на сервере уместно в регламентных заданиях и сервисных обработках администратора.
Что учесть перед распараллеливанием
| Вопрос | Почему важно |
|---|---|
| Объекты независимы? | Если два потока пишут один документ или одни записи регистра — блокировки и ошибки «данные изменены другим пользователем» |
| Узкое место — СУБД? | Если тормозит тяжёлый запрос, потоки будут ждать друг друга на СУБД, ускорения не будет |
| Сколько рабочих процессов у сервера? | Потоков больше, чем ядер, — переключение контекста, рост времени |
| Файловая база? | Параллельного выигрыша, как правило, нет |
| Нужна ли транзакционность целиком? | Порции выполняются в разных сеансах; общий откат невозможен |
Замер до и после обязателен: иногда три потока дают ускорение втрое, а иногда — ноль, потому что все упираются в одну таблицу.
Типичные ошибки
- Нет ожидания. Код считает работу законченной сразу после запуска, а следующий шаг читает необработанные данные.
- Метод не экспортный или в клиентском модуле. Задание завершится аварийно сразу после старта.
- Передача объектов вместо ссылок. Параметры сериализуются; передавайте ссылки и простые значения.
- Одно исключение валит всю порцию. Ловите ошибки по каждому объекту.
- Нет журнала. Ошибки фоновых заданий не видны пользователю — пишите их в журнал регистрации или возвращайте сводкой.
Фоновые задания ускоряют независимую работу. Если объекты конкурируют за одни данные, сначала уберите конкуренцию, потом добавляйте потоки.
Если после распараллеливания обработка всё равно медленная, причина обычно в запросах, блокировках или настройках сервера — это разбираю на аудите производительности 1С и при настройке сервера 1С.
Итог
- Делим массив на порции, на каждую запускаем
ФоновыеЗадания.Выполнитьс экспортным серверным методом. - Результат возвращаем через временное хранилище, ошибки ловим по каждому объекту.
- Ждём завершения через
ОжидатьЗавершенияВыполнения()и проверяемСостояние. - В интерактивных сценариях не блокируйте клиента ожиданием на сервере.
- Ускорение есть только для независимых объектов на клиент-серверной базе — проверяйте замером.




