Асинхронность в управляемом интерфейсе 1С

1С на управляемых формах теперь работает на большом количестве платформ – браузеры, мобильные телефоны, Windows, Mac, Linux.

Поэтому некоторые вещи пришлось исключать из 1С, чтобы обеспечить возможность выполнения на разных платформах. Среди этих вещей – синхронность выполнения.

Теперь код 1С должен писаться для асинхронного выполнения. Некоторые ошибочно воспринимают этот факт только в том ключе, что теперь в 1С запрещены модальные окна. Ничего подобного, модальные окна (блокирование всего интерфейса) по-прежнему доступны.

Асинхронность – это совершенно другое, оно затронуло даже то, что не касается интерфейса.

Синхронный и асинхронный код

При выполнении любого кода есть моменты, когда программа занимается ожиданием завершения длительной операции – реакции пользователя, распечатки документа, завершения поиска файлов в каталоге, ответа от интернет-сервера.

В синхронном коде выполняется цикл ожидания завершения длительной операции:

Процедура Работа()
        //Код до длительной операции   
        ВыполнитьДлительнуюОперацию();
                    Пока НЕ ОжиданиеЗавершено() Цикл
                    КонецЦикла
        //Код после длительной операции       
КонецПроцедуры
 

В асинхронном коде выполнение отдается системе при старте длительной операции и возвращается назад программе при завершении этой операции:

Процедура Работа()
        //Код до длительной операции   
        ВыполнитьДлительнуюОперацию(ПродолжениеРаботы);
КонецПроцедуры
Процедура ПродолжениеРаботы ()
        //Код после длительной операции       
КонецПроцедуры
 

В асинхронном коде появляется дробление кода на множество процедур. В-принципе, этого можно было бы избежать неявной генерацией процедур из кода. Т.е. код можно было бы писать как и раньше, система 1С сама бы генерировала процедуры на низком уровне:

Процедура Работа()
        //Код до длительной операции   
                    //На низком уровне завершал бы выполнение процедуры Работа
        ВыполнитьДлительнуюОперацию(ПродолжениеРаботы);  
        //Код после длительной операции, выносился бы в отдельную процедуру на низком уровне  
КонецПроцедуры
 

Процедура Работа может содержать локальные переменные, и вызов длительной процедуры может происходить из середины цикла.

Следовательно, 1С для возрождения контекста процедуры после возвращения выполнения из системы должна восстановить все локальные переменные, переменные цикла и войти так, чтобы оказаться на нужной итерации цикла.

1с не реализовала неявное преобразование обычного кода в асинхронный, переложив тяжесть реализации асинхронности на программиста.

Необходимость преобразования кода из синхронного в асинхронный связана с тем, что в некоторых платформах и системах нельзя крутить бесконечный цикл с вызовом DoEvents. Например, в браузерах выполнение кода должно завершаться в ограниченные сроки.

Асинхронное выполнение циклов

Асинхронное выполнение снижает читабельность и восприятие программы, провоцирует разбиение дробление кода на мелкие участки.

В синхронном режиме цикл можно было написать так:

Для Инд = 1 По Всего Цикл

        ВыполнитьДлительнуюОперацию();

        ВыполнитьДлительнуюОперацию2();

        //Операторы после длительных операций

КонецЦикла;

 

В асинхронном режиме цикл придется переписать так:

Перем мИнд; //Теперь глобальная переменная
мИнд = 0; //Как вариант мИнд = Неопределено;
ИтерацияЦиклаИнд();
Процедура ИтерацияЦиклаИнд()
        мИнд = мИнд + 1; //Как вариант мИнд = ? (мИнд = Неопределено, 1, мИнд + 1);
                    Если мИнд >  Всего Тогда
                            Возврат;
        КонецЕсли;
        ВыполнитьДлительнуюОперацию(ВыполнитьДлительнуюОперациюЗавершение);
КонецПроцедуры
 
Процедура ВыполнитьДлительнуюОперациюЗавершение()
        ВыполнитьДлительнуюОперацию2(ВыполнитьДлительнуюОперацию2Завершение);
КонецПроцедуры
 
Процедура ВыполнитьДлительнуюОперацию2Завершение()
                    //Операторы после длительной операций
                    ИтерацияЦиклаИнд (); //Аналог оператора Продолжить
КонецПроцедуры
 
 

Видно, что нужно явно прописывать вызов следующей итерации. Особенно это важно, если используется цепочка длительных операций, например: сначала получить от пользователя выбор файла, затем получить данные о нем из операционной системы, и т.п.

Переменная Инд для упрощения кода инкрементируется в процедуре итерации до вызова первой длительной операции. Поэтому Инд стартует со значения на единице меньше начального. Как вариант, можно инкрементировать Инд после сравнения с всего, а далее использовать не переменную мИнд, а переменную текущего элемента:

Если мИнд >  Всего Тогда
        Возврат;
        КонецЕсли;
мТекущийЭлемент = мТЗ[Инд];
мИнд = мИнд + 1;

Модальные формы

Что касается модальных форм, то это лишь один из примеров асинхронности. Пожалуй, самый доступный.

Когда вызывается модальная форма, то в асинхронной реализации мы должны прекратить выполнение кода 1с.

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

На самом деле в управляемых формах 1С есть остались модальные окна, это окна которые показываются в режиме «Блокировка всего интерфейса», просто они обрабатываются асинхронным способом.

Плоды асинхронности

Увеличение объема кода

Список процедур, которые требуют асинхронного выполнения, большой.  Это диалоги с пользователем, поиск файлов в каталоге, выполнение команд системы с ожиданием возврата.

Соответственно, код будет часто разбиваться на маленькие кусочки, дробиться на процедуры. Что не будет способствовать прозрачности и удобству восприятия кода.

С другой стороны, программиста все больше и больше приучают к клиент-серверному программированию в парадигме – «послал запрос – жди ответ».

Т.е. классическое программирование последовательного выполнения кода в 1С изживает себя, полностью ломая восприятие программиста для программирования под клиент-серверную архитектуру.

Код в очередной раз усложнился без видимых преимуществ для программиста.

Однако ничего не поделаешь, с этим придется жить и страдать. Интересно, что никакие другие системы кроме 1с не переложили реализацию асинхронности на программиста.

Сохранение и восстановление контекста выполнения

Если раньше код мог целиком выполняться на сервере, то теперь, при необходимости получить атрибуты файла или другой длительной операции, придется сохранять текущие рассчитанные на сервере данные в хранилище.  Причем сохранять не до следующего вызова сервера, а до востребования, потому что до момента, когда они понадобятся, сервер может быть вызван для других операций. Затем их восстанавливать и продолжать на очередной итерации. Т.е. накладные расходы увеличиваются. С другой стороны, по сравнению с длительным ожиданием результата операции накладные расходы по восстановлению контекста составляют крайне небольшой процент.

Но программисту, так или иначе, придется заботиться о сохранении контекста, что повлечет необходимость написания дополнительного кода. Очередное увеличение трудозатрат.

Независающие формы

Переход на асинхронный код приведет к тому, что даже без фоновых задач можно будет выполнять несколько операций одновременно.

Допустим, была обработка, которая в цикле обрабатывала документы. Управляемая форма передавала управление на сервер и там выполнялась обработка.  В асинхронном варианте придется обработать документ и дождаться возвращения управления от системы. Т.е. после передачи вызова в систему выполнение кода обработки прекратится до получения ответа и пользователь сможет в этом же приложении выполнять другие действия.

Пример асинхронного кода

Я написал обработку, которая выдает список файлов в каталоге. В отличии от типовой, можно обрабатывая отдельно подпапки, чтобы ненужные можно было исключить из результатов. Обработка поиска полностью асинхронная, попробуйте сравнить с обычной.

 

Скачать