Как стать автором
Обновить

Многопоточный процесс выполнения процедуры с помощью методов стандартных подсистем 1С

Время на прочтение7 мин
Количество просмотров10K

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

Введение

В этой статье решил привести небольшой программный эксперимент - позапускать собственную процедуру общего модуля конфигурации в многопоточном режиме, используя относительно новые методы библиотеки стандартных подсистем - набора модулей ДлительныеОперации. Разработку примеров я буду вести на типовой конфигурации БСП - версии 3.1.7 на Платформе 1с 8.3.20.

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

Напишем процедуру, которая будет использоваться в многопоточном запуске

В собственном общем модуле конфигурации (я работаю на типовой БСП 3.1.7), создаем искусственную процедуру, которую будем использовать в многопоточном запуске. Выглядит она пусть так:

&НаСервере
Процедура ПроцедураМногопоток(Поток, Параметры) Экспорт
  
	КоличествоСозданныхОбъектов = 0;
	
	Если Параметры.ТипОбработки = "Вариант 1" Тогда // Создадим 500 документов поступления  (можно и загрузить)
		
		Для Счетчик = 1 по 500 Цикл
			
			НовДок = Документы._ДемоПоступлениеТоваров.СоздатьДокумент();
			НовДок.Дата = ТекущаяДата();
			НовДок.Организация = Параметры.Организация;
			НовДок.Валюта = Справочники.Валюты.НайтиПоКоду("643"); 
			НовДок.Комментарий = Параметры.КомментарийДокумента;
			
			Попытка      
				НовДок.Записать(РежимЗаписиДокумента.Запись);
			Исключение
				
			КонецПопытки;	
			
			КоличествоСозданныхОбъектов = КоличествоСозданныхОбъектов + 1; 
			
		КонецЦикла;
		
	ИначеЕсли Параметры.ТипОбработки = "Вариант 2" Тогда	// Создадим 1000 записей справочника "Номенклатура"

		Для Счетчик = 1 по 1000 Цикл
			
			НовСпр = Справочники._ДемоНоменклатура.СоздатьЭлемент();
			НовСпр.Наименование = "Новая номенклатура_"+Строка(Счетчик);
			НовСпр.НаименованиеДляПечати = "Новая номенклатура_"+Строка(Параметры.ОписаниеСправочника);
			НовСпр.Записать();
			
		КонецЦикла;
		
		КоличествоСозданныхОбъектов = КоличествоСозданныхОбъектов + 1;
		
	КонецЕсли;
	
КонецПроцедуры

При первом типе обработке - "Вариант 1", процедура - будет создать 500 документов. При втором типе - "Вариант 2" - запустим цикл по созданию 1000 элементов справочника "Номенклатура".

Теперь, перейдем к коду обработки, использующим ДлительныеОперации, запускающим ж

 Описание функционала запуска с помощью функции "ВыполнитьПроцедуруВНесколькоПотоков"

Для начала нарисуем вот такую форму:

Рис.1 Форма для исследования многопоточности
Рис.1 Форма для исследования многопоточности

Напишем процедуру клиентского запуска. Выглядит она вот так:

&НаКлиенте
Процедура ЗапуститьМногопоток(Команда)
	
	ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект);
	
	
	Задание = СоздадимПотокиНаСервере(УникальныйИдентификатор);
	
	ИдентификаторЗадания = Задание.ИдентификаторЗадания;
	
	НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	НастройкиОжидания.ВыводитьОкноОжидания = Ложь;
	НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
	НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина;
	

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

Далее, функция СоздадимПотокиНаСервере(УИД)

&НаСервере
Функция СоздадимПотокиНаСервере(УникальныйИдентификатор)

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

	// ===== первый поток выполнения =====
	
	КодПотока = "Поток 1";
	ПараметрыПотока 						= ПараметрыМногопоточнойФункции();
	ПараметрыПотока.ТипОбработки 			= "Вариант 1";
	ПараметрыПотока.ОписаниеСправочника 	= Объект.ОписаниеСправочника; 
	ПараметрыПотока.КомментарийДокумента 	= Объект.КомментарийДокумента;
	ПараметрыПотока.Организация           	= Объект.Организация;	
	
	ПараметрыВызоваСервера = Новый Массив;
	ПараметрыВызоваСервера.Добавить(КодПотока); 		 // КодПотока
	ПараметрыВызоваСервера.Добавить(ПараметрыПотока);    // Параметры функции в потоке
	
	ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); 
	
	// ===== второй поток выполнения =====
	
	КодПотока = "Поток 2";
	ПараметрыПотока 						= ПараметрыМногопоточнойФункции();
	ПараметрыПотока.ТипОбработки 			= "Вариант 2";
	ПараметрыПотока.ОписаниеСправочника 	= Объект.ОписаниеСправочника; 
	ПараметрыПотока.КомментарийДокумента 	= Объект.КомментарийДокумента;
	ПараметрыПотока.Организация           	= Объект.Организация;	
	
	ПараметрыВызоваСервера = Новый Массив;
	ПараметрыВызоваСервера.Добавить(КодПотока); 		 // КодПотока
	ПараметрыВызоваСервера.Добавить(ПараметрыПотока);    // Параметры функции в потоке
	
	ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); 	
	
	// =================================== 
	
	ИмяФункцииИлиПроцедуры = "ОбщийМодуль1.ПроцедураМногопоток";
	
	ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода);
		
   	Если ФоновоеЗадание.Статус = "Ошибка" Тогда
		Сообщить(СокрЛП(ФоновоеЗадание.Статус));
	КонецЕсли;

	
	Возврат ФоновоеЗадание;	
	
КонецФункции

&НаСервере
Функция ПараметрыМногопоточнойФункции()
	
	Результат = Новый Структура();
	Результат.Вставить("ТипОбработки", 0);
	Результат.Вставить("ОписаниеСправочника", "");
	Результат.Вставить("КомментарийДокумента", "");
	Результат.Вставить("Организация", Справочники._ДемоОрганизации.ПустаяСсылка());
	Результат.Вставить("ЗагружатьПорциями", Истина);
	Возврат Результат;
	
КонецФункции

Здесь, я обозначаю условные параметры для двух потоков "Поток 1" и "Поток 2". Далее, использую Функцию "ВыполнитьПроцедуруВНесколькоПотоков" с этими параметрами.

Опишем функции "ПрогрессВыполнения" и "ОбработатьДанные" (это будут чисто-условные "полупустые" функции)

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

&НаСервереБезКонтекста
Функция ПрочитатьПрогресс(ИдентификаторЗадания)
	Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
КонецФункции

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

	Если Задание = Неопределено Тогда
		Возврат;
	КонецЕсли;  
	
	ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата));

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

Весь код модуля формы обработки вот такой (можно скопипастить):

&НаСервере
Функция ПараметрыМногопоточнойФункции()
	
	Результат = Новый Структура();
	Результат.Вставить("ТипОбработки", 0);
	Результат.Вставить("ОписаниеСправочника", "");
	Результат.Вставить("КомментарийДокумента", "");
	Результат.Вставить("Организация", Справочники._ДемоОрганизации.ПустаяСсылка());
	Результат.Вставить("ЗагружатьПорциями", Истина);
	Возврат Результат;
	
КонецФункции	

&НаКлиенте
Процедура ЗапуститьМногопоток(Команда)
	
	ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект);
	
	
	Задание = СоздадимПотокиНаСервере(УникальныйИдентификатор);
	
	//ИдентификаторЗадания = ПолучитьИЗВременногоХранилища(Задание.АдресРезультата).Получить("Поток 1").ИдентификаторЗадания;//Задание.ИдентификаторЗадания;
	
	ИдентификаторЗадания = Задание.ИдентификаторЗадания;
	//Сообщить(ИдентификаторЗадания);
	
	НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	НастройкиОжидания.ВыводитьОкноОжидания = Ложь;
	НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
	НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина;
	

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

&НаСервере
Функция СоздадимПотокиНаСервере(УникальныйИдентификатор)

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

	// ===== первый поток выполнения =====
	
	КодПотока = "Поток 1";
	ПараметрыПотока 						= ПараметрыМногопоточнойФункции();
	ПараметрыПотока.ТипОбработки 			= "Вариант 1";
	ПараметрыПотока.ОписаниеСправочника 	= Объект.ОписаниеСправочника; 
	ПараметрыПотока.КомментарийДокумента 	= Объект.КомментарийДокумента;
	ПараметрыПотока.Организация           	= Объект.Организация;	
	
	ПараметрыВызоваСервера = Новый Массив;
	ПараметрыВызоваСервера.Добавить(КодПотока); 		 // КодПотока
	ПараметрыВызоваСервера.Добавить(ПараметрыПотока);    // Параметры функции в потоке
	
	ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); 
	
	// ===== второй поток выполнения =====
	
	КодПотока = "Поток 2";
	ПараметрыПотока 						= ПараметрыМногопоточнойФункции();
	ПараметрыПотока.ТипОбработки 			= "Вариант 2";
	ПараметрыПотока.ОписаниеСправочника 	= Объект.ОписаниеСправочника; 
	ПараметрыПотока.КомментарийДокумента 	= Объект.КомментарийДокумента;
	ПараметрыПотока.Организация           	= Объект.Организация;	
	
	ПараметрыВызоваСервера = Новый Массив;
	ПараметрыВызоваСервера.Добавить(КодПотока); 		 // КодПотока
	ПараметрыВызоваСервера.Добавить(ПараметрыПотока);    // Параметры функции в потоке
	
	ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); 	
	
	// =================================== 
	
	ИмяФункцииИлиПроцедуры = "ОбщийМодуль1.ПроцедураМногопоток";
	
	ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода);
		
   	Если ФоновоеЗадание.Статус = "Ошибка" Тогда
		Сообщить(СокрЛП(ФоновоеЗадание.Статус));
	КонецЕсли;

	
	Возврат ФоновоеЗадание;	
	
КонецФункции	

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

&НаСервереБезКонтекста
Функция ПрочитатьПрогресс(ИдентификаторЗадания)
	Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
КонецФункции

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

	Если Задание = Неопределено Тогда
		Возврат;
	КонецЕсли;  
	
	ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата));
	
КонецПроцедуры

Заключение и выводы

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

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
Всего голосов 4: ↑3 и ↓1+2
Комментарии10

Публикации

Истории

Работа

Аналитик 1С
8 вакансий
Программист 1С
68 вакансий
Консультант 1С
96 вакансий

Ближайшие события

7 – 8 ноября
Конференция byteoilgas_conf 2024
МоскваОнлайн
7 – 8 ноября
Конференция «Матемаркетинг»
МоскваОнлайн
15 – 16 ноября
IT-конференция Merge Skolkovo
Москва
22 – 24 ноября
Хакатон «AgroCode Hack Genetics'24»
Онлайн
28 ноября
Конференция «TechRec: ITHR CAMPUS»
МоскваОнлайн
25 – 26 апреля
IT-конференция Merge Tatarstan 2025
Казань