v8: Асинхронные вычисления без «заморозки» формы (на фоновых заданиях)В бытность свою студентом, курсе на 1, открыл для себя в Delphi замечательную возможность создания многопоточных приложений. По делу и без дела, делал многопоточными все свои поделки – было интересно, хоть тогда у меня еще не было многоядерных процессоров. Постепенно мозги привыкли к этому, и когда я занялся 1С 8, меня ожидало разочарование – запущенный из формы код замораживал не только саму форму, но и окно приложения заодно. Грустно. «Финты ушами» с использованием генератора «Внешних событий» по душе не пришлись. А до фоновых заданий в версии 1С 8.1 добрался только сейчас. | | Автор статьи: shachneff | Редакторы: oleg_km, dj_serega, Последняя редакция №5 от 08.08.08 | История URL: http://kb.mista.ru/article.php?id=696 | |
Ключевые слова: 1cv81, фоновое задание, асинхронно, многопоточность
Дано: 1С:Предприятие > 8.1.8, клиент-серверная архитектура, MS SQL.
Общий неглобальный серверный модуль. Обработка с одной формой, одной кнопкой и одним табличным полем.
Цель: Нажав кнопку на форме, запустить некий долгий алгоритм расчета так, чтобы при этом форма была доступна для нажатия других кнопок, менюшек, перемещения. По окончании расчета передать результат расчета в табличное поле и отобразить результат.
Методика: Как показала практика, из отработавшего фонового задания вернуть штатным путем каке-либо данные невозможно. Имеется 2 способа, позволяющих это делать:
1) фоновое задание пишет результат своей работы в БД, обработка отслеживает, что фоновое задание завершилось и считывает из БД результат. В качестве места хранения результата предлагается использовать регистр сведений, где измерение хранит UID экземпляра фонового задания, а ресурс имеет тип ХранилищеЗначений.
2) извращенный способ – передать значение через программную генерацию исключения (оператор «ВызватьИсключение»).
Решение:
Описывать способ с регистром сведений не буду, так как это достаточно просто реализовать, а минусом является необходимость добавления в конфигурацию регистра
сведений. Поэтому опишу вариант с «ВызватьИсключение»:
Процедура общего модуля:
Процедура ФоноваяПроцедура(Вход) Экспорт
ВремяСтарта = ТекущаяДата();
Длит = 15; //15 секунд
Пока (ТекущаяДата() - ВремяСтарта) < Длит Цикл
//холостой цикл-замедлитель
КонецЦикла;
//чтобы не передавать примитивные типы,
//создадим ТЗ из двух колонок, в одну из которых положим значение входного параметра,
// а во вторую - выходного
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Вход");
ТЗ.Колонки.Добавить("Выход");
НС = ТЗ.Добавить();
НС.Вход = Вход;
НС.Выход = ТекущаяДата() + 3600;
//упакуем объект ТаблицаЗначений и сериализуем его в строку. Для больших таблиц - хороший выигрыш в объеме.
Упаковано = ЗначениеВСтрокуВнутр(Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(9)));
ВызватьИсключение Упаковано; //самое главное, обманем систему,сказав, что возникла ошибка и в качестве описания ошибки подсунем возвращаемое значение
КонецПроцедуры
Модуль формы обработки:
Перем Ключ;
Процедура КнопкаВыполнитьНажатие(Кнопка)
// размерность массива - по числу параметров запускаемой в фоновом режиме процедуры
МассивПараметров = Новый Массив(1);
МассивПараметров[0] = "123-входной параметр-строка";
Ключ = Новый УникальныйИдентификатор; //чтобы отличить наше фоновое задание от других
//внимание! Первый параметр - полный путь к запускаемой процедуре, включая имя общего модуля, в котором она находится.
ФоновыеЗадания.Выполнить("МодульРегламентныхЗаданий.ФоноваяПроцедура", МассивПараметров, Ключ, "Тестовое ФЗ"); // запуск
ПодключитьОбработчикОжидания("ЗаполнитьТП", 1); //ждем, пока ФЗ нам что-то вернет.
//Важно! В данном случае применить метод ОжидатьЗавершения не получится. Если получится - пишите как.
КонецПроцедуры
Процедура ЗаполнитьТП() //просто заполняет ТабличноеПоле на форме, демонстрируя, что все работает.
ФильтрОтбора = Новый Структура("Ключ,Наименование,Состояние", Ключ, "Тестовое ФЗ", СостояниеФоновогоЗадания.ЗавершеноАварийно);
МассивЗаданий = ФоновыеЗадания.ПолучитьФоновыеЗадания(ФильтрОтбора);
Если МассивЗаданий.Количество() > 0 И НЕ МассивЗаданий[0].ИнформацияОбОшибке.Описание = "" Тогда
//получили данные из Фонового задания, поместили их в Табличное поле
ТП = ЗначениеИзСтрокиВнутр(МассивЗаданий[0].ИнформацияОбОшибке.Описание).Получить();
ЭлементыФормы.ТП.СоздатьКолонки(); //отобразили то, что поместили.
ОтключитьОбработчикОжидания("ЗаполнитьТП"); //прекратили ожидать результатат от фонового задания.
КонецЕсли;
КонецПроцедуры
Результат:
Жмем кнопку. 15 секунд наслаждаемся тасканием формы и прочими действиями (кроме закрытия). Потом резко (само!!!) заполнится табличное поле на форме, чего и следовало ожидать.
Нагрузочные испытания проведены на передаче таблицы значений из 2 полей с количесвом строк 100 тыс. шт. – успешно. Ссылочные типы тоже передаются нормально (но опять же, только в упакованном виде).
Конец.
|