В данной статье рассмотрим примеры выполнения функций и процедур в многопоточном режиме, используя возможности Библиотеки стандартных подсистем.
Введение
В этой статье решил привести небольшой программный эксперимент - позапускать собственную процедуру общего модуля конфигурации в многопоточном режиме, используя относительно новые методы библиотеки стандартных подсистем - набора модулей ДлительныеОперации. Разработку примеров я буду вести на типовой конфигурации БСП - версии 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 элементов справочника "Номенклатура".
Теперь, перейдем к коду обработки, использующим ДлительныеОперации, запускающим ж
Описание функционала запуска с помощью функции "ВыполнитьПроцедуруВНесколькоПотоков"
Для начала нарисуем вот такую форму:

Напишем процедуру клиентского запуска. Выглядит она вот так:
&НаКлиенте Процедура ЗапуститьМногопоток(Команда) ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект); Задание = СоздадимПотокиНаСервере(УникальныйИдентификатор); ИдентификаторЗадания = Задание.ИдентификаторЗадания; НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект); НастройкиОжидания.ВыводитьОкноОжидания = Ложь; НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения; НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина; Обработчик = Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект); ДлительныеОперацииКлиент.ОжидатьЗавершение(Задание, Обработчик, НастройкиОжидания); КонецПроцедуры
Далее, функция СоздадимПотокиНаСервере(УИД)
&НаСервере Функция СоздадимПотокиНаСервере(УникальныйИдентификатор) ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор); ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Выполнение многопоточной функции'"); ПараметрыВыполнения.ЗапуститьВФоне = Истина; ПараметрыМетода = Новый Соответствие(); // ===== первый поток выполнения ===== КодПотока = "Поток 1"; ПараметрыПотока = ПараметрыМногопоточнойФункции(); ПараметрыПотока.ТипОбработки = "Вариант 1"; ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника; ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента; ПараметрыПотока.Организация = Объект.Организация; ПараметрыВызоваСервера = Новый Массив; ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); // ===== второй поток выполнения ===== КодПотока = "Поток 2"; ПараметрыПотока = ПараметрыМногопоточнойФункции(); ПараметрыПотока.ТипОбработки = "Вариант 2"; ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника; ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента; ПараметрыПотока.Организация = Объект.Организация; ПараметрыВызоваСервера = Новый Массив; ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСерв��ра); // =================================== ИмяФункцииИлиПроцедуры = "ОбщийМодуль1.ПроцедураМногопоток"; ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода); Если ФоновоеЗадание.Статус = "Ошибка" Тогда Сообщить(СокрЛП(ФоновоеЗадание.Статус)); КонецЕсли; Возврат ФоновоеЗадание; КонецФункции &НаСервере Функция ПараметрыМногопоточнойФункции() Результат = Новый Структура(); Результат.Вставить("ТипОбработки", 0); Результат.Вставить("ОписаниеСправочника", ""); Результат.Вставить("КомментарийДокумента", ""); Результат.Вставить("Организация", Справочники._ДемоОрганизации.ПустаяСсылка()); Результат.Вставить("ЗагружатьПорциями", Истина); Возврат Результат; КонецФункции
Здесь, я обозначаю условные параметры для двух потоков "Поток 1" и "Поток 2". Далее, использую Функцию "ВыполнитьПроцедуруВНесколькоПотоков" с этими параметрами.
Опишем функции "ПрогрессВыполнения" и "ОбработатьДанные" (это будут чисто-условные "полупустые" функции)
&НаКлиенте Процедура ПрогрессВыполнения(Результат, ДополнительныеПараметры) Экспорт КонецПроцедуры &НаСервереБезКонтекста Функция ПрочитатьПрогресс(ИдентификаторЗадания) Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания); КонецФункции &НаКлиенте Процедура ОбработатьДанные(Задание, ДополнительныеПараметры) Экспорт Если Задание = Неопределено Тогда Возврат; КонецЕсли; ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата)); КонецПроцедуры
Весь код модуля формы обработки вот такой (можно скопипастить):
&НаСервере Функция ПараметрыМногопоточнойФункции() Результат = Новый Структура(); Результат.Вставить("ТипОбработки", 0); Результат.Вставить("ОписаниеСправочника", ""); Результат.Вставить("КомментарийДокумента", ""); Результат.Вставить("Организация", Справочники._ДемоОрганизации.ПустаяСсылка()); Результат.Вставить("ЗагружатьПорциями", Истина); Возврат Результат; КонецФункции &НаКлиенте Процедура ЗапуститьМногопоток(Команда) ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПрогрессВыполнения", ЭтотОбъект); Задание = СоздадимПотокиНаСервере(УникальныйИдентификатор); //ИдентификаторЗадания = ПолучитьИЗВременногоХранилища(Задание.АдресРезультата).Получить("Поток 1").ИдентификаторЗадания;//Задание.ИдентификаторЗадания; ИдентификаторЗадания = Задание.ИдентификаторЗадания; //Сообщить(ИдентификаторЗадания); НастройкиОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект); НастройкиОжидания.ВыводитьОкноОжидания = Ложь; НастройкиОжидания.ОповещениеОПрогрессеВыполнения = ОповещениеОПрогрессеВыполнения; НастройкиОжидания.ВыводитьПрогрессВыполнения = Истина; Обработчик = Новый ОписаниеОповещения("ОбработатьДанные", ЭтотОбъект); ДлительныеОперацииКлиент.ОжидатьЗавершение(Задание, Обработчик, НастройкиОжидания); КонецПроцедуры &НаСервере Функция СоздадимПотокиНаСервере(УникальныйИдентификатор) ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор); ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Выполнение многопоточной функции'"); ПараметрыВыполнения.ЗапуститьВФоне = Истина; ПараметрыМетода = Новый Соответствие(); // ===== первый поток выполнения ===== КодПотока = "Поток 1"; ПараметрыПотока = ПараметрыМногопоточнойФункции(); ПараметрыПотока.ТипОбработки = "Вариант 1"; ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника; ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента; ПараметрыПотока.Организация = Объект.Организация; ПараметрыВызоваСервера = Новый Массив; ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); // ===== второй поток выполнения ===== КодПотока = "Поток 2"; ПараметрыПотока = ПараметрыМногопоточнойФункции(); ПараметрыПотока.ТипОбработки = "Вариант 2"; ПараметрыПотока.ОписаниеСправочника = Объект.ОписаниеСправочника; ПараметрыПотока.КомментарийДокумента = Объект.КомментарийДокумента; ПараметрыПотока.Организация = Объект.Организация; ПараметрыВызоваСервера = Новый Массив; ПараметрыВызоваСервера.Добавить(КодПотока); // КодПотока ПараметрыВызоваСервера.Добавить(ПараметрыПотока); // Параметры функции в потоке ПараметрыМетода.Вставить(КодПотока,ПараметрыВызоваСервера); // =================================== ИмяФункцииИлиПроцедуры = "ОбщийМодуль1.ПроцедураМногопоток"; ФоновоеЗадание = ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(ИмяФункцииИлиПроцедуры, ПараметрыВыполнения, ПараметрыМетода); Если ФоновоеЗадание.Статус = "Ошибка" Тогда Сообщить(СокрЛП(ФоновоеЗадание.Статус)); КонецЕсли; Возврат ФоновоеЗадание; КонецФункции &НаКлиенте Процедура ПрогрессВыполнения(Результат, ДополнительныеПараметры) Экспорт КонецПроцедуры &НаСервереБезКонтекста Функция ПрочитатьПрогресс(ИдентификаторЗадания) Возврат ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания); КонецФункции &НаКлиенте Процедура ОбработатьДанные(Задание, ДополнительныеПараметры) Экспорт Если Задание = Неопределено Тогда Возврат; КонецЕсли; ЭтаФорма.РезультатВыполнения = СокрЛП(Задание.Статус) +" "+СокрЛП(ПолучитьИЗВременногоХранилища(Задание.АдресРезультата)); КонецПроцедуры
Заключение и выводы
В статье попробовал использовать функционал многопоточности - запустил искусственную процедуру общего модуля с разными параметрами параллельно (при одних значениях параметрах). Задача выполнена. Спасибо за прочтение материала, надеюсь, что данная статья будет кому-то полезна.