Многопоточность в 1С: параллельная обработка данных фоновыми заданиями

01.09.26

База данных - HighLoad оптимизация

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

Что такое «поток» в 1С

Первое, что важно зафиксировать: классических потоков (thread) внутри одного контекста исполнения в 1С нет. Нельзя внутри процедуры «отпочковать» параллельную ветку, которая делит с вами переменные и память. Единица параллелизма в 1С — это фоновое задание: отдельный серверный сеанс со своей транзакцией, соединением с СУБД и изолированным контекстом.

Отсюда два следствия, которые определяют всю архитектуру решения:

  1. Задания не имеют общей памяти. Обмен данными идёт только через то, что переживает границу сеанса: базу данных, регистры, временное хранилище.
  2. Реальный параллелизм есть только в клиент-серверном варианте, где задания распределяются по рабочим процессам кластера. В файловой базе фоновые задания выполняются, но по очереди и с привязкой к инициировавшему сеансу — ускорения от «многопоточности» там ждать не стоит.

Отдельно стоит развести два разных понятия, которые часто путают:

  • Асинхронность на клиенте (Асинх/Ждать, методы Начать..., оповещения) — это про неблокирующий интерфейс. Один поток, просто управление возвращается в форму, пока идёт длительная операция. Ядра это не загружает.
  • Параллелизм на сервере (фоновые задания) — это про то, чтобы реально считать в несколько рук.

Дальше речь именно о втором.

 

Три уровня работы с фоновыми заданиями

Низкий уровень: менеджер ФоновыеЗадания

Базовый механизм — серверный менеджер ФоновыеЗадания. Он запускает на выполнение экспортную процедуру неглобального общего модуля:

// Запуск (серверный контекст)
Параметры = Новый Массив;
Параметры.Добавить(МассивСсылок);
Параметры.Добавить(АдресРезультата);

Задание = ФоновыеЗадания.Выполнить(
    "ОбработкаДанныхВызовСервера.ОбработатьПорцию", // ИмяМодуля.ИмяМетода
    Параметры,
    Новый УникальныйИдентификатор,                 // ключ
    "Обработка порции документов");                // наименование

Сам метод обработки:

// Общий модуль ОбработкаДанныхВызовСервера, флаг «Сервер», НЕ глобальный
Процедура ОбработатьПорцию(МассивСсылок, АдресРезультата) Экспорт

    Результат = Новый Массив;
    Для Каждого Ссылка Из МассивСсылок Цикл
        // ... прикладная логика по одному элементу ...
        Результат.Добавить(ОбработатьОдин(Ссылка));
    КонецЦикла;

    // Кладём результат туда, откуда его заберёт инициатор
    ПоместитьВоВременноеХранилище(Результат, АдресРезультата);

КонецПроцедуры

Ключевые ограничения этого уровня:

  • Запускается процедура, а не функция — вернуть значение напрямую нельзя. Результат передаётся через временное хранилище, регистр или запись в БД.
  • Метод должен быть экспортным и вызываемым на сервере. Внутри — никакого клиентского контекста и интерактивных методов.
  • Параметры сериализуются и передаются в другой сеанс, поэтому в них нельзя протаскивать, например, объект формы.

Дождаться завершения и проверить статус:

ФоновыеЗадания.ОжидатьЗавершенияВыполнения(Задание, 60); // таймаут в секундах

Если Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда
    ЗаписьЖурналаРегистрации("Обработка.Порция",
        УровеньЖурналаРегистрации.Ошибка, , ,
        ПодробноеПредставлениеОшибки(Задание.ИнформацияОбОшибке));
КонецЕсли;

 

Средний уровень: БСП, Длительные операции

В типовых на БСП обычно не работают с ФоновыеЗадания напрямую — используют подсистему «Длительные операции». Она оборачивает фоновое задание в удобный сценарий «запустил на сервере → жду на клиенте с индикатором → получил результат», сама разбирается с временным хранилищем и корректно обрабатывает отмену и ошибки.

&НаКлиенте
Процедура ВыполнитьОбработку(Команда)

    Операция = ЗапуститьНаСервере();

    ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
    ПараметрыОжидания.Заголовок = "Идёт обработка данных";

    ДлительныеОперацииКлиент.ОжидатьЗавершение(
        Операция,
        Новый ОписаниеОповещения("ПослеЗавершенияОбработки", ЭтотОбъект),
        ПараметрыОжидания);

КонецПроцедуры

&НаСервере
Функция ЗапуститьНаСервере()

    ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
    ПараметрыВыполнения.НаименованиеФоновогоЗадания = "Обработка данных";

    Возврат ДлительныеОперации.ВыполнитьФункцию(
        ПараметрыВыполнения,
        "ОбработкаДанныхВызовСервера.ВыполнитьРасчёт",
        ПараметрыРасчёта());

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

&НаКлиенте
Процедура ПослеЗавершенияОбработки(Результат, ДополнительныеПараметры) Экспорт

    Если Результат = Неопределено Тогда
        Возврат; // операцию отменили
    КонецЕсли;

    Если Результат.Статус = "Ошибка" Тогда
        ПоказатьПредупреждение(, Результат.КраткоеПредставлениеОшибки);
        Возврат;
    КонецЕсли;

    ДанныеРасчёта = ПолучитьИзВременногоХранилища(Результат.АдресРезультата);
    // ... вывод результата в форму ...

КонецПроцедуры

Здесь, в отличие от низкого уровня, запускается именно функция, а её возвращаемое значение БСП сама помещает во временное хранилище и отдаёт адрес в Результат.АдресРезультата. Для запуска сразу нескольких функций параллельно у подсистемы есть отдельный механизм (ВыполнитьФункцииПараллельно) — число одновременных заданий он подбирает адаптивно под возможности кластера; конкретный API смотрите в своей версии БСП через синтакс-помощник.

 

Фоновый уровень: регламентные задания

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

 

Практика: паттерн «разделяй и обрабатывай»

Типовая задача — обработать большой массив (документы за период, элементы справочника, строки загрузки) быстрее, чем в один поток. Схема почти всегда одинаковая:

  1. Собрать полный список объектов работы.
  2. Разбить его на N порций.
  3. Запустить N фоновых заданий, по заданию на порцию.
  4. Дождаться завершения всех.
  5. Собрать частичные результаты и обработать ошибки.

Хелпер разбиения на порции «по кругу» (равномерно раскладывает элементы):

Функция РазбитьНаПорции(МассивЭлементов, КоличествоПорций) Экспорт

    Порции = Новый Массив;
    Для Сч = 1 По КоличествоПорций Цикл
        Порции.Добавить(Новый Массив);
    КонецЦикла;

    Индекс = 0;
    Для Каждого Элемент Из МассивЭлементов Цикл
        Порции[Индекс % КоличествоПорций].Добавить(Элемент);
        Индекс = Индекс + 1;
    КонецЦикла;

    Возврат Порции;

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

Запуск и сбор:

Функция ОбработатьПараллельно(МассивСсылок, КоличествоПотоков) Экспорт

    Порции = РазбитьНаПорции(МассивСсылок, КоличествоПотоков);

    Задания = Новый Массив;
    Адреса  = Новый Массив;

    Для Каждого Порция Из Порции Цикл

        Если Порция.Количество() = 0 Тогда
            Продолжить;
        КонецЕсли;

        Адрес = ПоместитьВоВременноеХранилище(Неопределено, Новый УникальныйИдентификатор);
        Адреса.Добавить(Адрес);

        Параметры = Новый Массив;
        Параметры.Добавить(Порция);
        Параметры.Добавить(Адрес);

        Задания.Добавить(ФоновыеЗадания.Выполнить(
            "ОбработкаДанныхВызовСервера.ОбработатьПорцию",
            Параметры, , "Обработка порции"));

    КонецЦикла;

    // Ждём все
    Для Каждого Задание Из Задания Цикл
        ФоновыеЗадания.ОжидатьЗавершенияВыполнения(Задание);
    КонецЦикла;

    // Собираем результат
    ОбщийРезультат = Новый Массив;
    Для Каждого Адрес Из Адреса Цикл
        ЧастьРезультата = ПолучитьИзВременногоХранилища(Адрес);
        Если ЧастьРезультата <> Неопределено Тогда
            Для Каждого Элемент Из ЧастьРезультата Цикл
                ОбщийРезультат.Добавить(Элемент);
            КонецЦикла;
        КонецЕсли;
        УдалитьИзВременногоХранилища(Адрес);
    КонецЦикла;

    Возврат ОбщийРезультат;

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

Про число потоков. Соблазн взять «по числу ядер» обманчив: упираться будете чаще не в процессор сервера приложений, а в СУБД и в блокировки. Разумная практика — вынести количество в настройку (константу) и подбирать под конкретную нагрузку и оборудование, а не зашивать в код. В типовых на БСП эту заботу берёт на себя ДлительныеОперации.

 

Подводные камни

Передача данных между заданиями. Общей памяти нет. Всё, что нужно вернуть, идёт через временное хранилище (адрес создавайте с новым УникальныйИдентификатор, а не с идентификатором формы — иначе значение не переживёт до сбора результата), либо через регистр/таблицу БД. Не пытайтесь «поделиться» модульной переменной — в другом сеансе её просто нет.

Блокировки и взаимоблокировки. Это главная причина, по которой параллельная обработка иногда работает медленнее последовательной. Если два задания одновременно пишут в один и тот же объект метаданных или в пересекающиеся наборы записей регистра, начинаются ожидания на блокировках, а в худшем случае — deadlock. Лечится это на этапе проектирования порций: разбивайте данные так, чтобы задания не конкурировали за одни и те же записи — по организации, по складу, по диапазону дат, по хэшу ссылки. Управляемый режим блокировок и аккуратные управляемые блокировки обязательны.

Файловый режим. Повторюсь, потому что это частый источник разочарования: в файловой базе параллелизма нет. Код, который на боевом клиент-серверном сервере даёт ускорение в разы, на файловой базе разработчика будет работать не быстрее однопоточного варианта. Тестируйте прирост в клиент-серверном варианте.

Нагрузка и ресурсы. Фоновые задания не занимают клиентские лицензии, но создают серверные сеансы и соединения с СУБД. Десяток «тяжёлых» заданий способен положить СУБД по вводу-выводу. Число одновременных заданий ограничено настройками рабочих процессов кластера — бесконтрольный запуск сотни заданий не даст стократного ускорения, а забьёт очередь.

Отладка. Чтобы поймать отладчиком код внутри фонового задания, в настройках отладки должна быть включена отладка фоновых заданий (и серверных вызовов). Не полагайтесь только на отладчик: логируйте ход выполнения в журнал регистрации с общим ключом порции — по нему потом легко собрать картину по всем заданиям.

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

 

Короткий чек-лист перед внедрением

  • Задача действительно распараллеливается? Есть независимые порции, которые не конкурируют за одни записи?
  • Порции нарезаны так, чтобы минимизировать пересечение блокировок?
  • Результат и ошибки собираются и проверяются по каждому заданию?
  • Число потоков вынесено в настройку, а не зашито?
  • Прирост измерен в клиент-серверном варианте на реальном объёме, а не на файловой базе?
  • Есть логирование в журнал регистрации с ключом порции?

 

Заключение

Многопоточность в 1С — это не потоки внутри процедуры, а грамотное распределение работы по фоновым заданиям. Инструменты штатные и давно стабильные: менеджер ФоновыеЗадания для полного контроля, ДлительныеОперации из БСП для типового сценария с индикатором и результатом, регламентные задания для фона по расписанию. Основная сложность лежит не в запуске заданий, а в проектировании: как нарезать данные, чтобы задания не мешали друг другу, и как собрать результат. Если этот этап продуман, параллельная обработка честно превращает часы в минуты.

Вступайте в нашу телеграмм-группу Инфостарт

многопоточность фоновые задания параллельная обработка длительные операции БСП производительность 1С управляемые блокировки

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Механизмы платформы 1С Программист Бесплатно (free)

Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?

16.07.2025    42872    TitanLuchs    109    

153

Механизмы платформы 1С WEB-интеграция Программист 1С:Предприятие 8 Бесплатно (free)

В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.

14.01.2025    43687    dsdred    110    

155

Механизмы платформы 1С Программист Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

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

23.06.2024    38245    bayselonarrend    22    

180

HighLoad оптимизация Инструменты администратора БД Системный администратор Программист 1С 8.3 Абонемент ($m)

Обработка для простого и удобного анализа настроек, нагрузки и проблем с SQL сервером с упором на использование оного для 1С. Анализ текущих запросов на sql, ожиданий, конвертация запроса в 1С и рекомендации, где может тормозить.

10 стартмани

15.02.2024    24555    415    ZAOSTG    116    

132

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    35238    SeiOkami    48    

140

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    30826    YA_418728146    8    

175
Для отправки сообщения требуется регистрация/авторизация