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

от автора

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

Введение

В этой статье решил привести небольшой программный эксперимент — позапускать собственную процедуру общего модуля конфигурации в многопоточном режиме, используя относительно новые методы библиотеки стандартных подсистем — набора модулей ДлительныеОперации. Разработку примеров я буду вести на типовой конфигурации БСП — версии 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.ПроцедураМногопоток";  ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода);     Если ФоновоеЗадание.Статус = "Ошибка" Тогда Сообщить(СокрЛП(ФоновоеЗадание.Статус)); КонецЕсли;   Возврат ФоновоеЗадание;  КонецФункции  &НаКлиенте Процедура ПрогрессВыполнения(Результат, ДополнительныеПараметры) Экспорт  КонецПроцедуры  &НаСервереБезКонтекста Функция ПрочитатьПрогресс(ИдентификаторЗадания) Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания); КонецФункции  &НаКлиенте Процедура ОбработатьДанные(Задание, ДополнительныеПараметры) Экспорт  Если Задание = Неопределено Тогда Возврат; КонецЕсли;    ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата));  КонецПроцедуры

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

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


ссылка на оригинал статьи https://habr.com/ru/post/705840/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *