Как избежать 100% загрузки процессора при распараллеливании процессов в 1С?

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

Распараллеливание вычислений — это мощный инструмент повышения производительности, который позволяет сократить время выполнения тяжелых алгоритмов в разы. Однако, как справедливо замечено в обсуждении, бесконтрольное использование фоновых заданий может привести к «полке» в 100% загрузки центрального процессора (ЦП). В этот момент сервер перестает отвечать на запросы других пользователей, что критично для стабильной работы системы. Особенно остро эта проблема стоит для пользователей версии ПРОФ, где отсутствуют встроенные механизмы управления ресурсами, доступные в КОРП-версии.

В данной статье мы подробно разберем, как программно и системно ограничить аппетиты тяжелых алгоритмов, сохранив баланс между скоростью работы и стабильностью сервера. Мы рассмотрим методы контроля количества потоков, использование очередей и системные настройки операционной системы и SQL-сервера.

Метод 1. Программное ограничение количества потоков

Самый очевидный и действенный способ — не запускать потоков больше, чем сервер может переварить без ущерба для остальных задач. Если ваш алгоритм разбивает задачу на 20 частей и запускает их одновременно, сервер попытается выполнить их все сразу, задействуя все доступные ядра процессора через рабочий процесс rphost.

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


// Определяем максимально допустимое количество потоков
МаксПотоков = 4; 
МассивЗаданий = Новый Массив;

Для Каждого ПорцияДанных Из ОбщийНаборДанных Цикл
    
    // Проверяем количество текущих активных заданий
    Пока ФоновыеЗадания.ПолучитьФоновыеЗадания(Новый Структура("Состояние", СостояниеФоновогоЗадания.Активно)).Количество() >= МаксПотоков Цикл
        // Приостанавливаем выполнение основного потока, чтобы дать серверу подышать
        Приостановить(2); 
    КонецЦикла;
    
    ПараметрыЗапуска = Новый Массив;
    ПараметрыЗапуска.Добавить(ПорцияДанных);
    
    НовоеЗадание = ФоновыеЗадания.Выполнить("МойМодуль.ВыполнитьРасчет", ПараметрыЗапуска);
    МассивЗаданий.Добавить(НовоеЗадание);
    
КонецЦикла;

В этом примере мы используем метод ФоновыеЗадания.ПолучитьФоновыеЗадания() для мониторинга текущей нагрузки. Важно понимать, что каждый вызов серверного метода порождает новый поток внутри rphost, и ограничение их количества — это первый шаг к стабильности.

Метод 2. Использование семафора на базе регистра сведений

Если задача запускается разными пользователями одновременно, то локальный счетчик в коде одного пользователя не поможет. Выясним причину: каждый пользователь видит только свои задания или не знает о нагрузке, создаваемой коллегами. В этом случае нам поможет механизм «семафора».

Разберем реализацию по шагам:

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

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

Метод 3. Динамический мониторинг загрузки ЦП через WMI

Более продвинутый метод — принимать решение о запуске нового потока на основании реальной загрузки процессора в данный момент. Для этого в операционной системе Windows можно использовать инструментарий WMI (Windows Management Instrumentation). Проанализируем, как это можно сделать из кода 1С:


Функция ТекущаяЗагрузкаПроцессора()
    Service = ПолучитьCOMОбъект("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2");
    Processors = Service.ExecQuery("Select * from Win32_Processor");
    ОбщаяЗагрузка = 0;
    Колво = 0;
    Для Каждого Proc Из Processors Цикл
        ОбщаяЗагрузка = ОбщаяЗагрузка + Proc.LoadPercentage;
        Колво = Колво + 1;
    КонецЦикла;
    Возврат ?(Колво > 0, ОбщаяЗагрузка / Колво, 0);
КонецФункции

Используя эту функцию, мы можем настроить логику так: «Если загрузка процессора более 80%, подождать с запуском следующей порции данных». Это позволяет максимально эффективно использовать ресурсы сервера, не доводя его до критического состояния.

Метод 4. Настройка Processor Affinity для процессов rphost

Если программные методы по какой-то причине не подходят, рассмотрим системный уровень. Каждый рабочий процесс rphost.exe по умолчанию может использовать все доступные ядра процессора. Однако мы можем принудительно ограничить список ядер (Affinity Mask), на которых разрешено выполняться конкретному процессу.

Выясним, как это сделать:

Важный нюанс: В версии ПРОФ количество рабочих процессов ограничено. Если у вас один rphost, ограничение его ядер эффективно защитит сервер от полной заморозки, так как оставшиеся ядра будут свободны для нужд ОС и SQL-сервера.

Метод 5. Оптимизация SQL-сервера (Параметр MAXDOP)

Часто 100% загрузка ЦП вызвана не самим кодом 1С, а тем, что фоновые задания генерируют тяжелые SQL-запросы, которые распараллеливаются уже внутри СУБД. Проанализируем настройку MAXDOP (Maximum Degree of Parallelism).

Если в настройках SQL Server MAXDOP установлен в значение 0, то один тяжелый запрос из одного фонового задания может попытаться занять все ядра процессора. Для работы с 1С рекомендуется устанавливать это значение в пределах 1–4. Это ограничит количество ядер, выделяемых под один запрос, и «размажет» нагрузку, не позволяя одному пользователю монополизировать весь процессор сервера баз данных.

Метод 6. Использование очередей и «воркеров»

Рассмотрим архитектурный подход, который используется в крупных системах. Вместо того чтобы запускать задания по мере поступления, мы создаем Очередь задач. В системе постоянно работают 2–3 «воркера» (регламентных задания), которые раз в несколько секунд заглядывают в очередь и берут одну задачу в работу.

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

  1. Предсказуемая нагрузка на сервер в любое время суток.
  2. Отсутствие пиковых скачков при одновременном запуске задач многими пользователями.
  3. Возможность приоритизации (важные задачи выполняются первыми).

Итоги

Мы разобрали различные подходы к решению проблемы избыточной нагрузки при распараллеливании. Для достижения наилучшего результата мы рекомендуем комбинировать программные методы (ограничение количества активных ФоновыеЗадания) с системными настройками (ограничение MAXDOP в SQL). Это позволит вам сохранить высокую скорость обработки данных, не жертвуя при этом отзывчивостью системы для других пользователей.

← На главную