Содержание:
Файлы материала

Все серверные вызовы, которые могут длиться больше 8 секунд 1С рекомендует реализовывать через длительные операции, более подробно из официальных источников можно почитать тут.
В данной статье приведен пример расширения с демонстрацией работы длительной операции в несколько потоков (протестировано на ЗУП 3.1 с БСП 3.1.11.466).
Шаблон «Длительной операции с процентами» (без многопоточности) можно посмотреть тут.
Описание
Расширение состоит из обработки, в форме которой добавлена команда ВыполнитьОбработкуМногопоточно().
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
&НаКлиенте Процедура ВыполнитьОбработкуМногопоточно(Команда) // Объекты к многопоточной обработке СписокДокументов = ОбщегоНазначенияБЗККлиентСервер.ВыгрузитьКолонку(Объект.ДокументыКУдалению, "ДокументЛистокСообщенияДляВоенкомата"); // 1. Запуск фонового задания на сервере. ДлительнаяОперация = НачатьВыполнениеДолгойФункцииВНесколькоПотоков( УникальныйИдентификатор, СписокДокументов); // 2. Подключение обработчика завершения фонового задания. ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект); ПараметрыОжидания.Интервал = 1; ДлительныеОперацииКлиент.ОжидатьЗавершение( ДлительнаяОперация, Новый ОписаниеОповещения("ВыполнениеДолгойФункцииВНесколькоПотоковЗавершение", ЭтотОбъект), ПараметрыОжидания); КонецПроцедуры |
1. С помощью функции НачатьВыполнениеДолгойФункцииВНесколькоПотоков() инициализируем длительную операцию, разбиваем список объектов к обработке на порции, распределяем порции по потокам и далее запускаем выполнение «долгой» функции по обработке документов в несколько потоков.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
&НаСервереБезКонтекста Функция НачатьВыполнениеДолгойФункцииВНесколькоПотоков(Знач ИдентификаторФормы, Знач СписокДокументов) // Обработка может находится в модуль менеджере или в серверном общем модуле ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(ИдентификаторФормы); ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Получение сложных данных в несколько потоков'"); ПараметрыВыполнения.ЗапуститьВФоне = Истина; // Разбиваем список документов на порции, таким образом // что бы количество порций было равно количеству разрешенных потоков // и поместив порцию в массив устанавливаем в соответствие НаборПараметров с определенным ключем НаборПараметров = ПараметрыОбработкиДокументов(СписокДокументов); Возврат ДлительныеОперации.ВыполнитьФункциюВНесколькоПотоков( "Обработки.АВ_ОбработкаДлительнаяОперация.ПолучениеСложныхДанных", ПараметрыВыполнения, НаборПараметров); // Есть аналог с процедурой, соответсвенно в модуле менеджера должна быть процедура //ДлительныеОперации.ПараметрыВыполненияПроцедуры(); //ДлительныеОперации.ВыполнитьПроцедуруВНесколькоПотоков(); КонецФункции &НаСервереБезКонтекста Функция ПараметрыОбработкиДокументов(СписокДокументов) // Каждый элемент массива, который положили в значение соответсвия НаборПараметров, это отдельный // параметр в функции АВ_ОбработкаДлительнаяОперация.ПолучениеСложныхДанных(<Параметр1>, <Параметр2>, ...) // в данном случаи в первом параметре будех передаваться порция со списком документов, которая была добавлена // в строке: НаборПараметров.Вставить(НомерПотока, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПорцияОбъектов)); НаборПараметров = Новый Соответствие; ПорцияОбъектов = Новый Массив; КоличествоПотоковДлительныхОпераций = ДлительныеОперации.ДопустимоеКоличествоПотоков(); Если КоличествоПотоковДлительныхОпераций > 0 Тогда ЧислоОбъектовВПорции = Цел(СписокДокументов.Количество() / КоличествоПотоковДлительныхОпераций); Иначе ЧислоОбъектовВПорции = СписокДокументов.Количество(); КонецЕсли; // Разделение документов на порции по количеству потоков НомерПотока = 1; СчетчикОбъектов = 0; Для Каждого ТекущийДокумент Из СписокДокументов Цикл ЭтоПоследнийПоток = (НомерПотока = КоличествоПотоковДлительныхОпераций) Или (КоличествоПотоковДлительныхОпераций = 0); ПорцияОбъектов.Добавить(ТекущийДокумент); СчетчикОбъектов = СчетчикОбъектов + 1; Если СчетчикОбъектов = ЧислоОбъектовВПорции И Не ЭтоПоследнийПоток Тогда // Добавление порции в текущий поток НаборПараметров.Вставить(НомерПотока, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПорцияОбъектов)); ПорцияОбъектов = Новый Массив; СчетчикОбъектов = 0; НомерПотока = НомерПотока + 1; КонецЕсли; КонецЦикла; // Добавление порции в последний поток Если ПорцияОбъектов.Количество() Тогда НаборПараметров.Вставить(НомерПотока, ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ПорцияОбъектов)); КонецЕсли; Возврат НаборПараметров; КонецФункции |
Сама функция из модуля менеджера обработки, которой передается на выполнение каждый поток в этом примере выглядит так:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
// Здесь должен находиться код, определяющий выполнение длительной процедуры // // Параметры: // СписокДокументов - Массив // // Возвращаемое значение: // Результат - Число - Количество обработанных документов // Функция ПолучениеСложныхДанных(СписокДокументов) Экспорт Результат = 0; Всего = 100; Для Каждого ТекущийДокумент Из СписокДокументов Цикл // Сложная операция ДокументСсылка = ТекущийДокумент; ДокументОбъект = ДокументСсылка.ПолучитьОбъект(); ДокументОбъект.Записать(); Результат = Результат + 1; КонецЦикла; Возврат Результат; КонецФункции |
В качестве входного параметра функция принимает СписокДокументов. Как формируется состав параметров описано выше в функции ПараметрыОбработкиДокументов.
2. Вторым шагом в команде ВыполнитьОбработкуМногопоточно() был подключен обработчик завершения с вызовом экспортной функции ВыполнениеДолгойФункцииВНесколькоПотоковЗавершение(). При обработке результата получаем из временного хранилища сначала общий результат, затем в цикле результат по каждому потоку.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
&НаКлиенте Процедура ВыполнениеДолгойФункцииВНесколькоПотоковЗавершение(Результат, ДополнительныеПараметры) Экспорт Если Результат = Неопределено Тогда Возврат; КонецЕсли; Если Результат.Статус = "Ошибка" Тогда СтандартныеПодсистемыКлиент.ВывестиИнформациюОбОшибке(Результат.ИнформацияОбОшибке); Возврат; КонецЕсли; ДлительныеОперацииЗавершениеНаСервере(Результат.АдресРезультата); УдалитьИзВременногоХранилища(Результат.АдресРезультата); КонецПроцедуры &НаСервереБезКонтекста Процедура ДлительныеОперацииЗавершениеНаСервере(Знач АдресРезультата) Для каждого КлючИЗначение Из ПолучитьИзВременногоХранилища(АдресРезультата) Цикл Результат = КлючИЗначение.Значение; Если Результат.Статус = "Ошибка" Тогда ОбщегоНазначения.СообщитьПользователю(ОбработкаОшибок.КраткоеПредставлениеОшибки(Результат.ИнформацияОбОшибке)); Продолжить; // один поток упал, все равно продолжаем КонецЕсли; // Здесь должен быть код обработки полученного результата КоличествоОбработанныхДокументов = ПолучитьИзВременногоХранилища(Результат.АдресРезультата); ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку( НСтр("ru = 'Сложная операция выполнена. В потоке %1 обработано документов: %2'"), КлючИЗначение.Ключ, КоличествоОбработанныхДокументов); ОбщегоНазначения.СообщитьПользователю(ТекстСообщения); КонецЦикла; КонецПроцедуры |
Отладка
Для того, что бы поймать в отладчике выполнении «тяжелой» функции модуль менеджера, необходимо в меню Сервис -> Параметры написать в параметрах запуска РежимОтладки, но тогда соответственно процентов вы не увидите.

И включить автоматическое подключение фоновых заданий в меню Отладка -> Подключение -> Автоматическое подключение.
Образец расширения можно скачать в начале статьи.

Добрый день.
Тестировали на длительных операциях? Увеличивается скорость выполнения в многопотоке?
Добрый, не, сам не тестировал, попадался материал на infostart по зависимости времени выполнения от количества потоков https://infostart.ru/1c/articles/1812197/