Распараллеливание выполнения фонового задания

05.10.26

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

Параллельная обработка данных в фоновом задании, универсальная процедура.

Задача

Фоновое задание обрабатывает регистр сведений с накопленными данными, измерение договор, по результатам обработки что-то делается, записи из регистра удаляются. В тестовой базе отключены регламентные задания и накопилось больше 40 тысяч записей в регистре, при этом понадобилось чтобы записи отработали, но выяснилось, что в 1 поток записи будут обрабатываться часов 16, что не подходит. 

 

Решение

Выполнять обработку в несколько потоков, в итоге записи были обработаны в течение 1 часа. Была написана универсальная процедура, чтобы ее можно было использовать в аналогичных фоновых заданиях.

 

 

Код

Универсальная процедура

В нее передаются

  1. таблица значений с данными, 
  2. название колонки таблицы, по которой добавляются элементы в порцию
  3. имя вызвавшей процедуры для правильно нейминга создаваемых фоновых заданий
  4. имя процедуры, которая принмает порцию данных
Процедура ВыполнитьПроцедуруПорционно(ТаблицаДанных, ИмяВызвавшейПроцедуры, ИмяПроцедурыОбработкиПорции, ИмяКолонки, ЧислоПотоков = 0) Экспорт
	
    ЧислоСтрокВТаблице = ТаблицаДанных.Количество();
	
	Если ЧислоСтрокВТаблице = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Если ЧислоПотоков = 0 Тогда
		МаксимальноеЧислоПотоков = 16;
		ЧислоПотоков = Макс(Мин(Цел(ЧислоСтрокВТаблице / 500), МаксимальноеЧислоПотоков), 1);
	КонецЕсли;
	Если ЧислоПотоков = 1 Тогда
		ПорцияДанных = ТаблицаДанных.ВыгрузитьКолонку(ИмяКолонки);
		Выполнить(ИмяПроцедурыОбработкиПорции + "(ПорцияДанных)");
		Возврат;
	КонецЕсли;
	
    РазмерПорции 	= Цел(ЧислоСтрокВТаблице/ЧислоПотоков);
    МассивЗаданий 	= Новый Массив;
	ПорцияДанных 	= Новый Массив;
	Для НомерПотока = 1 По ЧислоПотоков Цикл
		
		ИндексНачала = (НомерПотока - 1)*РазмерПорции;
		ИндексКонца = ИндексНачала + РазмерПорции - 1;
		Если (НомерПотока = ЧислоПотоков) Тогда	
			ИндексКонца = ЧислоСтрокВТаблице - 1;			
		КонецЕсли;
		
	    ПорцияДанных.Очистить();
		Для Сч = ИндексНачала По ИндексКонца Цикл
			ПорцияДанных.Добавить(ТаблицаДанных[Сч][ИмяКолонки]);	
		КонецЦикла;
        НаборПараметров = Новый Массив;
        НаборПараметров.Добавить(ПорцияДанных);
        Задание = ФоновыеЗадания.Выполнить(ИмяПроцедурыОбработкиПорции, НаборПараметров,
		ИмяВызвавшейПроцедуры + НомерПотока, СтрШаблон("%1 (порция %2)", ИмяВызвавшейПроцедуры, НомерПотока));
        МассивЗаданий.Добавить(Задание);
    КонецЦикла;
    Если МассивЗаданий.Количество() > 0 Тогда
        Попытка
            ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий);
        Исключение
           мОшибка = ОписаниеОшибки();
           ЗаписьЖурналаРегистрации(ИмяВызвавшейПроцедуры + ".Ошибка", УровеньЖурналаРегистрации.Ошибка,,,мОшибка);
        КонецПопытки;
	КонецЕсли;
КонецПроцедуры

 

Фоновое задание, которое теперь работает параллельно

Процедура ОбновлениеСтатусов() Экспорт
	ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(Метаданные.РегламентныеЗадания.СтатусовДоговоров);
	
    Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Регистр.Договор КАК Договор
		|ИЗ
		|	РегистрСведений.ЗаданияПоОбновлениюСтатусовДоговоров КАК Регистр
		|ГДЕ
		|	НЕ Регистр.Ошибка
		|
		|СГРУППИРОВАТЬ ПО
		|	Регистр.Договор";
    
     ТаблицаДоговоров = Запрос.Выполнить().Выгрузить();
	ВыполнитьПроцедуруПорционно(ТаблицаДоговоров, "ОбновлениеСтатусов", "СтатусыДоговоровСервер.ОбновитьСтатусыДоговоров", "Договор");
  			
КонецПроцедуры

 

Процедура, обрабатывающая порцию данных

Процедура ОбновитьСтатусыДоговоров(МассивДоговоров) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	Регистр.Договор КАК Договор,
		|	Регистр.Статус КАК Статус
		|ИЗ
		|	РегистрСведений.ЗаданияПоОбновлениюСтатусовДоговоров КАК Регистр
		|ГДЕ
		|	НЕ Регистр.Ошибка
		|	И Регистр.Договор В(&МассивДоговоров)";
	Запрос.УстановитьПараметр("МассивДоговоров", МассивДоговоров);
	
	Выборка = Запрос.Выполнить().Выбрать();
	
	Пока Выборка.Следующий() Цикл
		
		НачатьТранзакцию();
		
		Попытка
			ОбновитьСтатусДоговора(Выборка.Договор, Выборка.Статус);
			МенеджерЗаписи 			= РегистрыСведений.ЗаданияПоОбновлениюСтатусовДоговоров.СоздатьМенеджерЗаписи();
			МенеджерЗаписи.Договор 	= Выборка.Договор;
			МенеджерЗаписи.Статус 	= Выборка.Статус;
			МенеджерЗаписи.Удалить();
			
			ЗафиксироватьТранзакцию();
		Исключение
			
			ОтменитьТранзакцию();
			мОшибка =  ОписаниеОшибки();
			
			МенеджерЗаписи 				= РегистрыСведений.ЗаданияПоОбновлениюСтатусовДоговоров.СоздатьМенеджерЗаписи();
			МенеджерЗаписи.Договор 		= Выборка.Договор;
			МенеджерЗаписи.Статус 		= Выборка.Статус;
			МенеджерЗаписи.Ошибка 		= Истина;
			МенеджерЗаписи.ТекстОшибки = мОшибка;
			МенеджерЗаписи.Записать();
			
		КонецПопытки;
		
	КонецЦикла;
	
КонецПроцедуры

 

Было сделано на основе статьи Как ускорить 1С – Многопоточная обработка данных

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

фоновые задания параллелизм многопоточность

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

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

См. также

HighLoad оптимизация Разработчик 1С 8.3 1С:ERP Управление предприятием 2 Бесплатно (free)

Использование оператора «В» для полей или данных составного типа (например, Регистратор) может приводить к неочевидным проблемам.

10.11.2025    15921    ivanov660    48    

58

HighLoad оптимизация Разработчик 1С:Предприятие 8 1C:ERP Бесплатно (free)

Приведем примеры использования различных в динамических списках и посмотрим, почему это плохо.

18.02.2025    16502    ivanov660    39    

62

HighLoad оптимизация Разработчик Россия Бесплатно (free)

А вы знали, что сервер 1С при соединении с базой на сервере PostgreSQL самостоятельно устанавливает некоторые параметры? Это важно знать при настройке сервера и отладке долгих запросов. Предлагаю разобраться.

27.08.2024    10420    soulner    10    

41

HighLoad оптимизация Технологический журнал Системный администратор Разработчик Бесплатно (free)

Обсудим поиск и разбор причин длительных серверных вызовов CALL, SCALL.

24.06.2024    19156    ivanov660    13    

64

HighLoad оптимизация Разработчик 1С:Предприятие 8 Бесплатно (free)

Метод очень медленно работает, когда параметр приемник содержит намного меньше свойств, чем источник.

06.06.2024    24998    Evg-Lylyk    73    

46

HighLoad оптимизация Разработчик 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Анализ простого плана запроса. Оптимизация нагрузки на ЦП сервера СУБД используя типовые индексы.

13.03.2024    14641    spyke    29    

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