Книга знаний

1С:Предприятие / v8 / Приемы программирования / Встроенный язык

v8: Асинхронные вычисления без «заморозки» формы (на фоновых заданиях)

В бытность свою студентом, курсе на 1, открыл для себя в Delphi замечательную возможность создания многопоточных приложений. По делу и без дела, делал многопоточными все свои поделки – было интересно, хоть тогда у меня еще не было многоядерных процессоров. Постепенно мозги привыкли к этому, и когда я занялся 1С 8, меня ожидало разочарование – запущенный из формы код замораживал не только саму форму, но и окно приложения заодно. Грустно. «Финты ушами» с использованием генератора «Внешних событий» по душе не пришлись. А до фоновых заданий в версии 1С 8.1 добрался только сейчас.Автор статьи: shachneff | Редакторы: oleg_km, dj_serega,
Последняя редакция №9 от 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 тыс. шт. – успешно. Ссылочные типы тоже передаются нормально (но опять же, только в упакованном виде).

Надеюсь, статья будет вам полезна.
Выражаю благодарность всем, кто помог мне осуществить данную операцию.

С уважением, Алексей Шачнев.


Конец.


Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2025 | Mista.ru

Яндекс.Метрика