Сколько параллельных фоновых заданий можно запускать в 1С для загрузки данных?

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

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

Определение оптимального количества потоков

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

  1. Расчет от количества ядер CPU: Базовое практическое правило для вычислительных задач и алгоритмов в 1С — выделять от 1 до 2 потоков на одно физическое ядро (или логический поток процессора с учетом Hyper-Threading). Если на десктопной или тестовой машине доступно 4 ядра, оптимально запускать от 2 до 4 потоков. На мощных серверах с двумя процессорами по 8 ядер и включенным Hyper-Threading (32 логических ядра) допустимо масштабирование до 16–32 параллельных заданий.
  2. Поправка на другие службы: Вычисляя лимит фоновых заданий, обязательно учитываем, что процессорное время делят между собой операционная система, СУБД (Microsoft SQL Server или PostgreSQL), рабочие процессы кластера 1С, а также сеансы обычных пользователей. Запуск 50 тяжелых потоков на сервере, не обладающем соответствующим запасом свободных ядер, приведет лишь к конкуренции за процессорные кванты и общему замедлению системы.
  3. Эмпирический подбор: Как показывает практика, предельная производительность всегда находится экспериментально под конкретный сценарий. Нередко 10 параллельных потоков показывают ту же общую скорость, что и 40, но при этом требуют в разы меньше оперативной памяти и не вызывают блокировок данных.

Ресурсные ограничения платформы и архитектурные ловушки

Выясним причину, почему нельзя бездумно создавать произвольное количество фоновых задач (например, 50 или 100), даже если задача кажется независимой.

  1. Режим информационной базы: В файловом варианте одновременное выполнение фоновых заданий заблокировано — платформа может исполнять только одно задание в единицу времени. Полноценный параллелизм доступен исключительно в клиент-серверном варианте работы.
  2. Расход оперативной памяти и перезапуск процессов: Каждое фоновое задание инициирует отдельное соединение к СУБД и выделяет область памяти в рабочем процессе кластера rphost. Если в кластере 1С настроены параметры «Максимальный объем памяти рабочих процессов» или «Безопасный расход памяти за один вызов», взрывной рост потребления памяти потоками приведет к аварийному завершению и перезапуску рабочих процессов кластера, что прервет выполнение всех параллельных задач.
  3. Управляемые блокировки и дедлоки: Если параллельные потоки не просто считают данные в памяти, а выполняют запись в общие справочники, документы или регистры сведений, неизбежно возникнут конфликты блокировок (Deadlock) и таймауты ожидания. Потоки необходимо изолировать по диапазонам записываемых ключей или префиксам.

Типичная ошибка: передача номеров строк большого текстового файла

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


// Ошибочный подход для огромных файлов
ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(ПутьКФайлу);
ПараметрыЗадания.Добавить(100000); // Номер начальной строки
ПараметрыЗадания.Добавить(150000); // Номер конечной строки

ФоновыеЗадания.Выполнить("ОбщийМодульЗагрузки.ЗагрузитьДиапазон", ПараметрыЗадания);

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

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

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

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

  1. Использование пула заданий вместо единовременного старта: Вместо одновременного запуска всего массива порций запускаем мастер-процесс. Он держит фиксированное число активных заданий (например, 8) и ожидает освобождения слота с помощью метода ФоновыеЗадания.ОжидатьЗавершения(), после чего запускает следующую порцию.
  2. Оптимизация режима записи объектов: Внутри кода фонового модуля перед сохранением элементов справочников или документов обязательно устанавливаем свойство Загрузка = Истина. Это отключает избыточные проверки и тяжелые обработчики событий (ПередЗаписью, ПриЗаписи), существенно снижая нагрузку на процессор и вероятность блокировок.
  3. Фиксация порциями: Не держите всю загрузку в одной транзакции. Разделяйте запись данных на порции фиксированного размера (по 1000–5000 записей) в рамках явных вызовов НачатьТранзакцию() и ЗафиксироватьТранзакцию(), чтобы не переполнять журнал транзакций СУБД.

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


// Массив с именами предварительно нарезанных файлов
МассивФайлов = ПолучитьСписокФайловПорций();
МаксимумПотоков = 4; // Рассчитано исходя из доступных ядер CPU

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

Для Каждого ИмяФайла Из МассивФайлов Цикл

    Пока АктивныеЗадания.Количество() >= МаксимумПотоков Цикл
        // Ожидаем завершения хотя бы одного задания из пула
        ЗавершенноеЗадание = ФоновыеЗадания.ОжидатьЗавершения(АктивныеЗадания, 5);
        Если ЗавершенноеЗадание <> Неопределено Тогда
            АктивныеЗадания.Удалить(АктивныеЗадания.Найти(ЗавершенноеЗадание));
        КонецЕсли;
    КонецЦикла;

    ПараметрыЗадания = Новый Массив;
    ПараметрыЗадания.Добавить(ИмяФайла);

    НовоеЗадание = ФоновыеЗадания.Выполнить("ОбщийМодульЗагрузки.ОбработатьФайлПорции", ПараметрыЗадания);
    АктивныеЗадания.Добавить(НовоеЗадание);

КонецЦикла;

// Ожидаем завершения оставшихся заданий
Если АктивныеЗадания.Количество() > 0 Тогда
    ФоновыеЗадания.ОжидатьЗавершения(АктивныеЗадания);
КонецЕсли;

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

← На главную