Введение
Всем доброго времени суток! В этой статье я решил привести небольшой программный эксперимент - позапускать собственную процедуру общего модуля конфигурации в многопоточном режиме, используя относительно новые методы библиотеки стандартных подсистем - набора модулей ДлительныеОперации. Разработку примеров я буду вести на типовой конфигурации БСП - версии 3.1.6.137 на Платформе 1с 8.3.20.1674. Однако, я пока не берусь утверждать, что данный подход можно использовать в любой современной конфигурации, в основе которой лежит БСП - поскольку этот функционал относительно новый. Но, со временем, его можно будет применить.
Статью разобью стандартной на две части - в первой части я опишу процедуру, которая должна будет запускаться многопоточно, во второй части - опишу практическое использование запуска в несколько потоков - ВыполнитьПроцедуруВНесколькоПотоков.
Переходим к первой части статьи.
Напишем процедуру, которая будет использоваться в многопоточном запуске
В собственном общем модуле конфигурации (я работаю на типовой БСП 3.1.6.13), создаем искусственную процедуру, которую будем использовать в многопоточном запуске. Выглядит она пусть так:
&НаСервере
Процедура ПроцедураМногопоток(Поток, Параметры) Экспорт
КоличествоСозданныхОбъектов = 0;
Если Параметры.ТипОбработки = "Вариант 1" Тогда // Создадим 500 документов поступления (можно и загрузить)
Для Счетчик = 1 по 500 Цикл
НовДок = Документы._ДемоПоступлениеТоваров.СоздатьДокумент();
НовДок.Дата = ТекущаяДата();
НовДок.Организация = Параметры.Организация;
НовДок.Валюта = Справочники.Валюты.НайтиПоКоду("643");
НовДок.Комментарий = Параметры.КомментарийДокумента;
Попытка
НовДок.Записать(РежимЗаписиДокумента.Запись);
Исключение
КонецПопытки;
КоличествоСозданныхОбъектов = КоличествоСозданныхОбъектов + 1;
КонецЦикла;
ИначеЕсли Параметры.ТипОбработки = "Вариант 2" Тогда // Создадим 1000 записей справочника "Номенклатура"
Для Счетчик = 1 по 1000 Цикл
НовСпр = Справочники._ДемоНоменклатура.СоздатьЭлемент();
НовСпр.Наименование = "Новая номенклатура_"+Строка(Счетчик);
НовСпр.НаименованиеДляПечати = "Новая номенклатура_"+Строка(Параметры.ОписаниеСправочника);
НовСпр.Записать();
КонецЦикла;
КоличествоСозданныхОбъектов = КоличествоСозданныхОбъектов + 1;
КонецЕсли;
КонецПроцедуры
При первом типе обработке - "Вариант 1", процедура - будет создать 500 документов. При втором типе - "Вариант 2" - запустим цикл по созданию 1000 элементов справочника "Номенклатура".
Теперь, перейдем к коду обработки, использующим ДлительныеОперации, запускающим ж
Описание функционала запуска с помощью функции "ВыполнитьПроцедуруВНесколькоПотоков"
Для начала нарисуем вот такую форму:
Рис.1 Форма тестирования многопотоковой функции в БСП
Напишем процедуру клиентского запуска. Выглядит она вот так:
&НаКлиенте
Процедура ЗапуститьМногопоток(Команда)
ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект);
Задание = СоздадимПотокиНаСервере(УникальныйИдентификатор);
ИдентификаторЗадания = Задание.ИдентификаторЗадания;
НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
НастройкиОжидания.ВыводитьОкноОжидания = Ложь;
НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина;
Обработчик = Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(Задание, Обработчик, НастройкиОжидания);
КонецПроцедуры
Далее, опишем функцию СоздадимПотокиНаСервере(УИД)
&НаСервере
Функция СоздадимПотокиНаСервере(УникальныйИдентификатор)
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Выполнение многопоточной функции'");
ПараметрыВыполнения.ЗапуститьВФоне = Истина;
ПараметрыМетода = Новый Соответствие();
// ===== первый поток выполнения =====
КодПотока = "Поток 1";
ПараметрыПотока = ПараметрыМногопоточнойФункции();
ПараметрыПотока.ТипОбработки = "Вариант 1";
ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника;
ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента;
ПараметрыПотока.Организация = Объект.Организация;
ПараметрыВызоваСервера = Новый Массив;
ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока
ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке
ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера);
// ===== второй поток выполнения =====
КодПотока = "Поток 2";
ПараметрыПотока = ПараметрыМногопоточнойФункции();
ПараметрыПотока.ТипОбработки = "Вариант 2";
ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника;
ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента;
ПараметрыПотока.Организация = Объект.Организация;
ПараметрыВызоваСервера = Новый Массив;
ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока
ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке
ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера);
// ===================================
ИмяФункцииИлиПроцедуры = "ОбщийМодуль1.ПроцедураМногопоток";
ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода);
Если ФоновоеЗадание.Статус = "Ошибка" Тогда
Сообщить(СокрЛП(ФоновоеЗадание.Статус));
КонецЕсли;
Возврат ФоновоеЗадание;
КонецФункции
&НаСервере
Функция ПараметрыМногопоточнойФункции()
Результат = Новый Структура();
Результат.Вставить("ТипОбработки", 0);
Результат.Вставить("ОписаниеСправочника", "");
Результат.Вставить("КомментарийДокумента", "");
Результат.Вставить("Организация", Справочники._ДемоОрганизации.ПустаяСсылка());
Результат.Вставить("ЗагружатьПорциями", Истина);
Возврат Результат;
КонецФункции
Здесь, я обозначаю условные параметры для двух потоков "Поток 1" и "Поток 2". Далее, использую Функцию "ВыполнитьПроцедуруВНесколькоПотоков" с этими параметрами.
Далее, опишем функции "ПрогрессВыполнения" и "ОбработатьДанные" (это будут чисто-условные "полупустые" функции)
&НаКлиенте
Процедура ПрогрессВыполнения(Результат, ДополнительныеПараметры) Экспорт
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПрочитатьПрогресс(ИдентификаторЗадания)
Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
КонецФункции
&НаКлиенте
Процедура ОбработатьДанные(Задание, ДополнительныеПараметры) Экспорт
Если Задание = Неопределено Тогда
Возврат;
КонецЕсли;
ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата));
КонецПроцедуры
Весь код модуля формы обработки вот такой (можно скопипастить):
&НаСервере
Функция ПараметрыМногопоточнойФункции()
Результат = Новый Структура();
Результат.Вставить("ТипОбработки", 0);
Результат.Вставить("ОписаниеСправочника", "");
Результат.Вставить("КомментарийДокумента", "");
Результат.Вставить("Организация", Справочники._ДемоОрганизации.ПустаяСсылка());
Результат.Вставить("ЗагружатьПорциями", Истина);
Возврат Результат;
КонецФункции
&НаКлиенте
Процедура ЗапуститьМногопоток(Команда)
ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект);
Задание = СоздадимПотокиНаСервере(УникальныйИдентификатор);
//ИдентификаторЗадания = ПолучитьИЗВременногоХранилища(Задание.АдресРезультата).Получить("Поток 1").ИдентификаторЗадания;//Задание.ИдентификаторЗадания;
ИдентификаторЗадания = Задание.ИдентификаторЗадания;
//Сообщить(ИдентификаторЗадания);
НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
НастройкиОжидания.ВыводитьОкноОжидания = Ложь;
НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения;
НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина;
Обработчик = Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(Задание, Обработчик, НастройкиОжидания);
КонецПроцедуры
&НаСервере
Функция СоздадимПотокиНаСервере(УникальныйИдентификатор)
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Выполнение многопоточной функции'");
ПараметрыВыполнения.ЗапуститьВФоне = Истина;
ПараметрыМетода = Новый Соответствие();
// ===== первый поток выполнения =====
КодПотока = "Поток 1";
ПараметрыПотока = ПараметрыМногопоточнойФункции();
ПараметрыПотока.ТипОбработки = "Вариант 1";
ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника;
ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента;
ПараметрыПотока.Организация = Объект.Организация;
ПараметрыВызоваСервера = Новый Массив;
ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока
ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке
ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера);
// ===== второй поток выполнения =====
КодПотока = "Поток 2";
ПараметрыПотока = ПараметрыМногопоточнойФункции();
ПараметрыПотока.ТипОбработки = "Вариант 2";
ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника;
ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента;
ПараметрыПотока.Организация = Объект.Организация;
ПараметрыВызоваСервера = Новый Массив;
ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока
ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке
ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера);
// ===================================
ИмяФункцииИлиПроцедуры = "ОбщийМодуль1.ПроцедураМногопоток";
ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода);
Если ФоновоеЗадание.Статус = "Ошибка" Тогда
Сообщить(СокрЛП(ФоновоеЗадание.Статус));
КонецЕсли;
Возврат ФоновоеЗадание;
КонецФункции
&НаКлиенте
Процедура ПрогрессВыполнения(Результат, ДополнительныеПараметры) Экспорт
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПрочитатьПрогресс(ИдентификаторЗадания)
Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
КонецФункции
&НаКлиенте
Процедура ОбработатьДанные(Задание, ДополнительныеПараметры) Экспорт
Если Задание = Неопределено Тогда
Возврат;
КонецЕсли;
ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата));
КонецПроцедуры
На видео исполнение процедуры выглядит вот так (не смог разместить здесь гиф-ку - поэтому ссылка на облако):
Заключение и выводы
В данной статья я попробовал использовать функционал многопоточности - запустил искусственную процедуру общего модуля с разными параметрами параллельно (при одних значениях параметрах . Задача выполнена. Но, к своему удивлению, я не обнаружил функционала многопоточности - именно ВыполнитьПроцедуруВНесколькоПотоков и ВыполнитьФункциюВНесколькоПотоков в современных (предпоследних типовых) - я посмотрел лишь некоторые (здесь не буду утверждать).
Предыдущие материалы по выполнению функций и процедур в асинхронном режиме
Ранее, на портале я приводил небольшие примеры по использованию функций и процедур в асинхронных режимах в рамках библиотеки стандартных подсистем:
БСП - рабочие примеры асинхронного запуска функций и процедур
Далее - другие материалы по разным возможностям библиотеки стандартных подсистем.
Мои материалы по возможностям Библиотеки стандартных подсистем (БСП)
Спасибо всем, кто прочитал до данного момента.
Также прошу ознакомиться с другими моими статьями по интересному функционалу типовых конфигураций в рамках библиотеки стандартных подсистем и по разделам. Я накопил достаточный объем знаний по данной библиотеки, вот наиболее интересные статьи по ней:
Возможности администрирования баз и кластера с помощью библиотеки стандартных подсистем:
Профили управления доступом к объектам в любой конфигурации на БСП
Журнал регистрации - основные методы работы через БСП
Базовые приемы работы с кластером 1С при помощи БСП
Работа со штрихкодами и печатными макетами с помощью библиотеки стандартных подсистем:
Генерация штрихкодов с помощью БСП для программистов
Печать макета MS Word в любом документе с помощью БСП
Префиксация объектов - полезный типовой функционал БСП
Работаем с контактной информацией в конфигурациях на БСП
Разные прикладные разработки:
Генератор маршрута по "документам отгрузки" в Google.Maps
Честный знак - запрос содержания упаковки по ее коду [табачная продукция]