Асинхронное нечто, или так, как раньше!
Разработка - Механизмы платформы 1С
Я вот никак не хотел больше писать статьи, т.к. лениво, да и на работе много интересного. Но сердце все-равно рвется из груди в попытках донести крупицы мудрости (ну или глупости - все зависит от аудитории). И чтобы не растекаться мыслью по древу, перейду к сути...
ВВЕДЕНИЕ
Суть в том, что с какой-то (вроде бы 8.3.18+) версии платформы появились у 1С асинхронные варианты методов для диалоговых окон, копирования файлов, подключения внешних компонент и всего того, что немного раньше делалось при помощи объекта "ОписаниеОповещения", представляющего из себя организацию "промиса" (того самого "обещания" из асинхронного программирования). Но код с "коллбэками" (обратными вызовами) был несколько громоздким. Да, 1С сделала в конфигураторе опцию рефакторинга, который старый синхронный вызов автоматически преобразовывал в новый асинхронный, но все-равно кода стало больше, а больше - это запутаннее. В том же менеджере работы с оборудованием передача "промисов" между функциями существенно затрудняла анализ и обратный инжиниринг для выколупывания протоколов работы с ВК.
Итак, "промисы" в первой итерации от 1С получились громоздкими, запутывали код, превращали его в "спагетти" без всех этих операторов безусловного перехода. И однажды 1С все же решила сделать тот самый await, который сразу и сильно упростил код, возвратив его обратно к линейной последовательности строк.
В своей статье предлагаю рассмотреть подходы к асинхронным диалогам и обращу внимание на некоторые особенности отдельных случаев. Надеюсь, что после прочтения этой статьи Вы перестанете писать "неасинхронно", даже если Ваша конфигурация до сих пор на обычных формах ("моя" - да).
В путь!
ИСТОРИЧЕСКИЙ ЛИКБЕЗ
Когда деревья были большими, а партизаны - толстыми, все программирование было линейным. Код выполнялся строка за строкой. Потом пришел Дейкстра и придумал процедурное программирование. Потом пришел Страуструп и придумал объекты. Нет, я не утверждаю, что это были именно Дейкстра и Страуструп, но они у меня четко так ассоциируются с вот этими двумя эпохами.
Дальше закон Мура стал тормозить, стало активно развиваться параллельное программирование, когда задача решалась сначала на множестве компьютеров, потом на множестве процессоров в одном компьютере, потом на множестве ядер в одном процессоре, а сейчас уже на множестве ядер на ускорителях (видеокартах и прочих специализированных устройствах). Наступила эра параллельного программирования, о которой я писал аж дважды: тыдыщь и тыдыщь.
Ну и где-то тут появилась и асинхронность, как механизм утилизации производительности одного ядра. Т.е. асинхронность - это способность выполнять несколько задач на одном ядре, переключая задачи в моменты ожидания. И вот мне почему-то кажется, что данный момент многие программисты как-то опускают. А ведь компьютер стал достаточно "сложным организмом", в нем помимо центрального процессора есть еще овер дофига других. Сначала это были математические (арифметические) сопроцессоры, с ними все эти процессоры управления памятью и внешними шинами (северные и южные мосты), потом графические ускорители, физические ускорители, тензорные и прочие процессоры для задач "искусственного интеллекта" (перемножения матриц и прочего их преобразования, с чем неплохо справляются и видеокарты - попер маркетинг).
И вот во всем этом море устройств операционная система уже не могла оставаться просто "многопоточной", к многопоточности добавилась асинхронность (в принципе это уже давно так - прерывания рулят), которая потихонечку прописалась в API.
Итак, к чему это я? К тому, чтобы читатель некоторым образом увидел историю развития и ощутил проблемы, которые решались в ходе развития, т.к. согласно ТРИЗ, все улучшения упираются в какие-то ухудшения, появляются качели эффективности, выражающиеся в том, что решение одной проблемы может породить несколько других проблем на другом уровне, которые нужно тоже как-то комплексно решать: разнести во времени (циклы чтения/записи памяти) или пространстве (ядра процессора), поменять отношение (50 градусов - когда-то это была высокая температура для процессора, а сейчас это вообще очень холодно, а 80 градусов стало почти нормой под нагрузкой).
Ну а дальше перейдем к асинхронности 1С.
РАНЬШЕ (за "миллион лет" до н.э.)
В старых версиях платформы обычные формы вполне себе работали с так называемой модальностью - кода открытие диалогов блокирует форму и ждет события с результатом. Выглядело это как-то так:
Результат = ОткрытьФормуМодально(ИмяФормы, Параметры, ...);
Ну и в переменной "Результат" появлялись данные выбора. Для диалогов использовалось что-то типа "Выбрать" или "Ввести" (ВвестиСтроку/Число/Дату/Значение). Таким образом код останавливался и ждал, когда пользователь что-то выберет, после чего можно было бы спокойно и без нервотрепки обработать результат.
Какие у этого минусы? Да, собственно, никаких для обычного разработчика. В то, что 1С не смогла прилично реализовать это для веб-клиента, я не верю. Единственный, на мой скромный взгляд, смысл в этом только как следование за трендами. Но в части диалогов модальный вызов ничем не отличается от немодального. В части подключения внешних компонент это уже оправдано, т.к. они вполне могут ожидать какие-то данные от оборудования при инициализации, которые при асинхронном подходе действительно будут сокращать время запуска 1С. То же самое и с копированием файлов - это позволяет пользователю не ждать завершения их копирования и перейти к другим задачам. Но тут экономия времени минимальна.
ПЕРВЫЙ БЛИН...
Да, первая реализация асинхронности была так себе - код стал запутанным. Функции "Выбрать*" превратились в "ПоказатьВыбор*", функции "Ввести*" в "ПоказатьВвод*", в "ОткрытьФорму" появилась возможность получить и обработать результат выбора с помощью отдельной процедуры, которая могла располагаться не только в форме, но и в общем модуле. Но для всего этого потребовалось писать еще одну процедуру на каждый диалог выбора/ввода/формы. В части кода, то он мог быть сгеренирован платформой, но его просто тупо становилось больше. Зато многие получили и профит - писали одну процедуру на множество диалогов, а иногда даже выносили это в отдельный модуль. В общем помимо проблем такой подход породил и новые возможности организации кода, его структурирования.
В общем, был ли этот блин комом или нет - решать вам, господа и товарищи читатели.
АСИНХ
И вот появился тот самый Асинх, ради которого я снова решил писать много букв. С одной стороны, этот суффикс получили все старые диалоговые методы/функции. Т.е. вот как-то так менялись названия: "Выбор*" -> "ПоказатьВыбор*" -> "Выбор*Асинх". Помимо этого у процедур и функций появился префикс "Асинх", который указывает, что процедура асинхронная.
Давайте разберемся с тем, как теперь это работает. Я, например, не увидел понимания этого у многих своих коллег, поэтому даже планирую провести на эту тему внутреннее обучение.
Итак, работает это все просто.
1. Вы вызываете асинхронную функцию.
2. Асинхронная функция помещается в очередь на выполнение.
3. Вместо результата планировщик (или как его там назвать) возвращает объект типа "Обещание" (промис), фактически адрес структуры состояния функции.
4. Чтобы получить результат, вам надо подождать. В 1С сделали тот самый "Ждать Обещание".
И вроде бы что это дает? Да вот нифига пока* не дает, но позволяет вернуться к старому, т.е. делать все почти также, как делали это в стародревние времена.
* Жду асинхронных запросов к HTTP-сервисам - там резон действительно есть.
ПРИМЕРЫ
Давайте разберем "исторические" примеры превращения кода из модального в асинхронный.
Модальный код:
Диалог = Новый ДиалогВыбораФайлов(Режим);
Если Диалог.Выбрать() Тогда
ИмяФайла = Диалог.ПолноеИмяФайла;
КонецЕсли;
Код с описанием оповещения:
Диалог = Новый ДиалогВыбораФайлов(Режим);
Диалог.Показать(Новый ОписаниеОповещения("ПриВыбореФайла", "ЭтаФорма", ДополнительныеПараметры));
...
&НаКлиенте
Процедура ПриВыбореФайла(Результат, ДополнительныеПараметры) Экспорт
Если ЗначениеЗаполнено(Результат) Тогда
ИмяФайла = Результат[0];
КонецЕсли;
КонецПроцедуры
Код увеличился, появилась еще одна процедура. Благо, что ее можно было засунуть хоть в общий модуль и вообще сделать одну процедуру на все случаи жизни.
Асинхронно:
&НаКлиенте
Асинх Процедура ВыбратьИмяФайла(Команда)
Диалог = Новый ДиалогВыбораФайлов(Режим);
Результат = Ждать Диалог.ВыбратьАсинх();
Если ЗначениеЗаполнено(Результат) Тогда
ИмяФайла = Результат[0];
КонецЕсли;
КонецПроцедуры
Смотрите, если мы вызываем этот код, как команду, то в стандартной процедуре обработки команды нужно прописать префикс "Асинх". Это связано с тем, что оператор "Ждать" можно вызывать только в асинхронных процедурах и функциях.
Кстати, смотрел один ролик, в котором автор говорил, что смысла в асинхронных процедурах вроде как нет, ибо "Ждать" возвращает результат обещания, а он имеет смысл только в функциях. Я, лично, считаю наоборот, т.к. "самописная" асинхронная функция ничего не дает, если внутри нее не вызывается асинхронный диалог или копирование файлов, подключение внешних компонент и все такое прочее асинхронное. А вот асинхронная процедура позволяет использовать "Ждать"*.
1С: Асинх / Async представляет собой модификатор, который может применяться к процедуре или функции, написанной на встроенном языке. Использование данного модификатора делает процедуру или функцию асинхронной. Важной особенностью является также то, что оператор Ждать может использоваться только внутри Асинх процедур/функций.
Т.е. у нас "Ждать" из обычной процедуры вызвать нельзя, поэтому процедуры обработки событий формы (команд и прочих мест), которые предполагают использование асинхронных диалогов, должны теперь быть с префиксом "Асинх". Городить дополнительные функции для этого не нужно.
Кстати, заметил, что если в диалоге нажать отмену, то код после "Ждать" не выполняется. Таким образом можно вообще не проверять переменную на заполненность, а отмена выбора в цепочке вопросов приведет к дальнейшей отмене всей оставшейся цепочки. Но тут могу быть неправ - проверяйте.
ОСОБЕННОСТИ
Основной особенностью новой жизни (ну помимо дописывания префикса "Асинх" к событиям формы) является то, что 1С будет исполнять асинхронную функцию уже после того, как отработает "базовое событие" формы. Что под этим подразумевается? То, что если у вас есть событие с аргументом "СтандартнаяОбработка", то вне зависимости от того, что там внутри этого кода произошло, система после выхода из процедуры будет смотреть на этот флаг, и если он в Истина, то будет произведена стандартная отработка. Например, для таблицы значений будет открыто значение, для табличного документа тоже. С асинхронными функциями сложнее, т.к. они будут работать уже после того, как стандартное событие отработает. И если Вы внутри такой функции поставите "СтандартнаяОбработка = ложь", то система это не увидит, ибо она обработает стандартное событие до того, как асинхронная функция вернет хоть какой-то результат.
Как бороться? Правильно, вызывать асинхронную процедуру из синхронного обработчика событий.
ВЫВОД
Основной вывод: опять получилось букв больше, чем хотелось бы. Ну и второй вывод: юзайте асинхронные диалоги, т.к. они экономят строки кода.
ВСЕМ ДОБРА!
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
Механизмы платформы 1С Разработчик Бесплатно (free)
Разберем 15 мифов о работе платформы «1С:Предприятие 8» – как распространенных, так и малоизвестных. Начнем с классики: «Код, написанный в одну строку, работает быстрее, чем многострочный». Так ли это на самом деле?
16.07.2025 45590 TitanLuchs 109
Работа с интерфейсом WEB-интеграция Механизмы платформы 1С Бесплатно (free)
Веб-интерфейсы повышают качество внешнего вида приложений 1С, предсказуемы с точки зрения верстки, позволяют организовать удобные и высокопроизводительные рабочие места для пользователей. Расскажем об особенностях разработки веб-интерфейсов на React внутри 1С, двустороннем взаимодействии 1С и JavaScript, а также сборке веб-приложения в одностраничный файл.
19.06.2025 18621 zeegin 15
Механизмы платформы 1С Работа с интерфейсом Разработчик Стажер 1С:Предприятие 8 Бесплатно (free)
Про ООП в 1С и о том, как сделать свой код более кратким и выразительным при помощи использования текучего интерфейса (fluent interface).
03.02.2025 25982 bayselonarrend 127
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
В этой статье подробно рассматривается работа с JSON в XDTO в 1С:Предприятие. Вы узнаете, как сериализовать и десериализовать объекты XDTO в JSON, интегрировать 1С с веб-сервисами и API, а также корректно обрабатывать данные при обмене. Разбираются особенности работы с коллекциями, использование функций восстановления и частые ошибки при работе с JSON и XDTO.
30.01.2025 33213 user2122906 10
Механизмы платформы 1С Файловый обмен (TXT, XML, DBF), FTP Разработчик 1С:Предприятие 8 Бесплатно (free)
Этот материал познакомит вас с механизмом XDTO (XML Data Transfer Objects) в 1С и научит эффективно использовать его возможности. Мы разберёмся, как работать с XML-схемами, создавать модели данных, манипулировать объектами XDTO, а также сериализовать и десериализовать их в XML. Вы узнаете, как использовать XDTO для интеграции с внешними системами, избегать типичных ошибок и оптимизировать код. К концу вы будете уверенно применять XDTO для решения сложных задач обмена данными и автоматизации процессов.
17.01.2025 55620 user2122906 13
Механизмы платформы 1С WEB-интеграция Разработчик 1С:Предприятие 8 Бесплатно (free)
В платформе 8.3.27 появилась возможность использовать WebSocket-клиент. Давайте посмотрим, как это все устроено и чем оно нам полезно.
14.01.2025 46728 dsdred 110
Механизмы платформы 1С Разработчик 1С:Предприятие 8 Бесплатно (free)
Особенности "Знач" и разбор документации к нему.
10.01.2025 26409 VAAngelov 60
Механизмы платформы 1С Разработчик Стажер 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)
Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.
23.06.2024 40405 bayselonarrend 24
Не знаю как просто в диалогах, а про ПолучитьФайл(ы)ССервераАсинх в СП есть следующая ремарка: "Результат выполнения обещания заполняется сразу (в веб-клиенте - до показа диалога, в остальных клиентах - после показа диалога) значением Неопределено."
По человечески это означает то что в веб-клиенте Обещание выполняется сразу как и последующий код в то время как диалог мозолит пользователю глаза. Будьте внимательны, коллеги.
Ответ от телеграмм канала 1С: «А что непонятного то? Уж куда проще, чем ОписаниеОповещения»… "
Ну и примерно об этом статья...
Для себя же пока не реализовал подобное в браузере не понял как это в принципе может реализоваться, только тогда и понимание встало на место -
А видео - да, отличное! Очень рекомендую всем посмотреть.
И если Вы внутри такой функции поставите "СтандартнаяОбработка = ложь", то система это не увидит, ибо она обработает стандартное событие до того, как асинхронная функция вернет хоть какой-то результат.Не так.
В асинхронные процедуры и функции параметры передаются по значению, а не по ссылке, поэтому менять значения параметров, в том числе ставить СтандартнаяОбработка = Ложь в асинхронных процедурах/функциях не имеет смысла, т.к. они никуда не вернутся.
Вот только сегодня с утра пытался вспомнить - есть ли асинх метод для ОткрытьФорму() и таки его нет, хотя тут возникает вопрос - возможно ли это вообще?
(18)Попробовал вот так
&НаКлиенте
асинх функция ОткрытьФормуАсинх(ПутьКФрме, ПараметрыФормы=неопределено)
Поток = Новый ПотокВПамяти();
оп = Новый ОписаниеОповещения("ОткрытьФормуЗавершение",ЭтаФорма,
Новый Структура("ДополнительныеПараметры, Семафор, Результат",
?(ТипЗнч(ПараметрыФормы)=Тип("Структура") И ПараметрыФормы.Свойство("ДополнительныеПараметры"), ПараметрыФормы.ДополнительныеПараметры,неопределено),
Поток));
ОткрытьФорму(ПутьКФрме,ПараметрыФормы,?(ТипЗнч(ПараметрыФормы)=Тип("Структура") И ПараметрыФормы.Свойство("Владелец"), ПараметрыФормы.Владелец,неопределено),,,,оп);
Пока ждать Поток.РазмерАсинх()=0 Цикл
КонецЦикла;
КонецФункции
&НаКлиенте
асинх процедура ОткрытьФормуЗавершение(Результат, ДополнительныеПараметры) экспорт
ДополнительныеПараметры.Вставить("Результат", Результат);
ждать ДополнительныеПараметры.Поток.ЗаписатьАсинх(Новый БуферДвоичныхДанных(1),0,1);
Конецпроцедуры
ПоказатьНо не получилось - просто
Пока ждать Поток.РазмерАсинх()=0 Цикл
КонецЦикла;
блокируете ГУИ намертво.
Хотя в других ЯП await на одном асинхронном методе позволяет выполняться "параллельном" асинхронному методу - но ГУИ - это особый случай, хотя ничто особо не должно было мешать 1С сделать так, чтобы ожидание не блокировало ГУИ - хоть какая-то значимая польза была бы!
Я не путаю асинхронность и многопоточность.
Но могу сказать следующее - асинхронность гроша ломанного не стоит без многопоточности!
Даже если её явно в нет в месте, где вызывается асинхронный метод. Так или иначе - за всей системной асинхронностью лежит многопоточность! А точнее - многозадачность - а Вы знаете в чём разница?
Если не будет многозадачности - то вся эта асинхронность - не более чем синхронность!
&НаКлиенте
асинх функция ОткрытьФормуАсинх(ПутьКФрме, ПараметрыФормы=неопределено)
Поток = Новый ПотокВПамяти();
оп = Новый ОписаниеОповещения("ОткрытьФормуЗавершение",ЭтаФорма,
Новый Структура("ДополнительныеПараметры, Семафор, Результат",
?(ТипЗнч(ПараметрыФормы)=Тип("Структура") И ПараметрыФормы.Свойство("ДополнительныеПараметры"), ПараметрыФормы.ДополнительныеПараметры,неопределено),
Поток));
ОткрытьФорму(ПутьКФрме,ПараметрыФормы,?(ТипЗнч(ПараметрыФормы)=Тип("Структура") И ПараметрыФормы.Свойство("Владелец"), ПараметрыФормы.Владелец,неопределено),,,,оп);
Пока ждать Поток.РазмерАсинх()=0 Цикл
КонецЦикла;
КонецФункции
ПоказатьТоже самое что
&НаКлиенте
функция ОткрытьФормух(ПутьКФрме, ПараметрыФормы=неопределено)
Поток = Новый ПотокВПамяти();
ОткрытьФорму(ПутьКФрме,ПараметрыФормы,?(ТипЗнч(ПараметрыФормы)=Тип("Структура") И ПараметрыФормы.Свойство("Владелец"), ПараметрыФормы.Владелец,неопределено));
Пока ждать Поток.Размер()=0 Цикл
КонецЦикла;
КонецФункции
ПоказатьАсинхронность нужна для эффективного управления многопоточностью - для организации многозадачности!
Но да - она бывает и навязанной в однопоточных контурах!
В 1С 8.3 - асинхронность навязана браузерами - которые перешли от однопоточных к многопоточным процессам, и интегрировались с асинхронными функциями от ОС (где тоже развивалась многопоточность).
Но если копнуть ещё глубже - то в ОС эта асинхронность тоже возникла не на пустом месте - её корни в процессах, которые как раз стали параллельными: либо из-за перехода железа, условно на новое оборудование, которое могло выполнять действия без участия центрального процессора, либо с развитием межпроцессных и даже меж системных взаимодействий, где процессы сами по себе параллельны (тут уже не буду вдаваться в особенности когда это один и тот же CPU для разных процессов, а уж когда CPU/компьютеры различные - то это тоже понятно).
Те же дисковые операции или сетевое взаимодействие - всё связано с процессами, которые сами по себе выполняются параллельно. И даже интерактивная работа с несколькими окнами - благодаря многозадачным ОС - тоже фактически стала параллельной - ведь, условно, пользователь - это тоже отдельная параллельная и, надо полагать, обычно, многозадачная система!
И на этом всё было построено много системных и библиотечных абстракций, которые стали предлагать асинхронность, за которой скрывалась обеспечение многозадачности!
И в других платформах даже в рамках одного потока можно спокойно асинхронно запустить, скажем поиск файлов, или запись в поток, или обращение к WEB-ресурсу, или открытие окна - и заняться прочими процессами, в т.ч. интерактивными - а потом уже готовые получить результаты такой асинхронной операции. И даже можно запустить несколько таких асинхронных вызовов независимо (условно, квазипараллельно) друг другу.
Безусловно, внутри таких вызовов - если не будет скрытой системной многопоточности, то всё выполнение будет синхронно - но оно будет квазиасинхронно - т.к. в таких функциях (если они грамотно используют системную асинхронность) так или иначе будут вызовы, которые будут взаимодействовать с тем или иным параллельным процессом! И даже если это взаимодействие будет просто банальным периодическим мониторингом сигнала или скрытым обратным вызовом - это не будет требовать постоянного выполнения кода на CPU - и многозадачное ядро системы сможет быстро переключаться между контролем таких процессов - ища тот, где можно продолжать выполнение - это и есть квазиасинхронность - код выполняется синхронно - но частями - чередуя разные блоки.
И, когда в прикладном приложении выстраивается асинхронный однопоточный код - он может так же дробиться на блоки - которые будут более эффективно расходовать процессорное время, и переключаться между разными алгоритмами!
и в коде выше - 1С вполне могла бы приостановить выполнение кода
Пока ждать Поток.РазмерАсинх()=0 Цикл
КонецЦикла;
и передать управление в
&НаКлиенте
асинх процедура ОткрытьФормуЗавершение(Результат, ДополнительныеПараметры) экспорт
ДополнительныеПараметры.Вставить("Результат", Результат);
ждать ДополнительныеПараметры.Поток.ЗаписатьАсинх(Новый БуферДвоичныхДанных(1),0,1);
Конецпроцедуры
где, скорее всего, уже подвиснет
ждать ДополнительныеПараметры.Поток.ЗаписатьАсинх(Новый БуферДвоичныхДанных(1),0,1);
пока не выполнится
Пока ждать Поток.РазмерАсинх()=0 Цикл
КонецЦикла;
и выход из той функции
Либо надо убрать "ждать" из
ждать ДополнительныеПараметры.Поток.ЗаписатьАсинх(Новый БуферДвоичныхДанных(1),0,1);
тогда сначала закончится выполнение кода асинх процедура ОткрытьФормуЗавершение(Результат, ДополнительныеПараметры) экспорт
Либо где-то в другом месте будет очередное "ждать"
Так выстраивается конечный автомат вызовов!
Разворачивающий в однопоточном контуре асинхронные вызовы в синхронные!
Но в других платформах применение "ждать" при асинхронности тоже не обязательно - условно там есть можно получить обещание/задачу контроллер = Поток.РазмерАсинх();
И проверить, выполнена она уже - или нет! Не замораживая текущий программный поток.
А так же мануально её прервать, ждать с таймаутом, ждать окончания нескольких, в т.ч. любой из нескольких.
Да - так конечный автомат не строится - и в однопоточном контуре не удастся достичь квазиасинхронности! Но если внутри, так-или иначе, буду скрыты многопоточные контуры - то это будет эффективно работать!
А без этого всего - вся эта асинхронность в 1С 8.3 - не более чем синтаксический сахар над уродливыми асинхронными функциями, применение которых навязывается лишь браузерами для WEB-клиента. Поэтому их нет в серверном контексте (а в других платформах как раз в серверном контексте асинхронность очень популярна как раз ради повышения эффективности управления потоками). Нет её и в клиент-серверном взаимодействии - где априори многозадачность - но 1С упорно хочет считать такие взаимодействия однозадачными и строго синхронными!
И, на мой взгляд, от этих конструкций в 1С 8.3 (асинх/ждать, как и от отдельных асинхронных функций) вообще можно было обойтись - просто в браузере вместо синхронных функций через "ждать" вызывать асинхронную, а исходные функции 1С сразу считать асинхронными - перестраивая код их компиляции соответствующим образом!
То есть - просто скрыть асинхронность за синхронностью - так как для программиста и для пользователя - это ничего не меняет - зато не возникает ложных ожиданий о параллельном выполнении!
Хотя, лично я считаю, что в 1С Предприятие как раз очень не хватает параллельности хотя бы квазипараллельной - на квазиасинхрнности - когда формально нет фоновых потоков, но код разных блоков может порциями выполняться на одном потоке, чередуясь.
Как при клиент-серверном взаимодействии (в т.ч. по WEB) так и в серверном контексте, так и в клиентском!
Но, видимо, 1С Предприятие 8.x до этого уже не дорастёт - слишком много надо концептуально дорабатывать! Это Вам не синтаксический сахар асинх/ждать подсунуть - тут виртуальную машину надо дорабатывать!
Да и, в WEB клиенте браузеры реально ограничивают контекст одним потоком выполнения (но - там есть некоторые пути обхода этого ограничения - хотя бы для организации квазипараллельности или даже для изолированные фоновых клиентских заданий - это можно было бы реализовать) - на других же клиентах/базовых платформах среды исполнения - можно было бы и полноценную параллельность сделать!
А-синхронность = отсутствие синхронности.
Вся суть только в том, что у виртуальной машины, интерпретирующей код 1Са, есть место, где кончаются команды. В синхронности окончание команд - это остановка. В оконных менеджерах операционных систем это просто "слушание" событий, которые в окно приходят. Нет событий - нет команд. Все команды - это реакция на события.
В асинхронности когда команды кончаются, начинаются асинхронные команды. Т.е. программа просто в цикле вызывает асинхронные процедуры/функции и помещает ответы в те самые ожидания. Если заюзать "Ждать" (await), то программа пойдет исполнять цикл асинхронных процедур/функций, дожидаясь появления результата той функции, которую ждем.
Отсюда простая мораль: асинхронность - это для ввода/вывода, сетей, диалогов пользователя и прочих моментов, в которых ответ появляется не сразу.
Вот, например, возьмем какой-нить буст и С++. Там есть целый asio, в котором реализованы функции для асинхронного доступа. Стандартный кейс - сетевое взаимодействие. Как сделано? Получаешь контекст соединения, вызываешь для него функции установки соединения, рукопожатия, прочих подготовительных моментов. Дальше ждешь, пока тебе не придет сообщение или отправляешь это сообщение, потом отвечаешь, потом снова ждешь еще одного сообщения и т.д. Так вот синхронное и асинхронное отличается тем, что когда ты синхронно ждешь сообщения, то ты не можешь послать в это время что-то из этого потока. Да, в принципе ты можешь сделать это из другого потока, но это в принципе как-то нехорошо выглядит. А когда у тебя асинхронно, то ты асинхронную функцию вешаешь на входящее сообщение, при том ты можешь отправлять туда раз в минуту какой-то пинг, повесив асинхронную функцию на таймер. И после того, как функция отработала, поймав событие, ты должен ее перезапустить, т.е. снова инициировать функции чтения и таймера.
И все это отличается тем, что в случае синхронного доступа ты тупо крутишь бесконечный цикл, в котором "while (1) myconnect.read();", а в асинхронном просто "ioc.run()" - это как раз и есть внутренний цикл asio контекста, который 1С от программиста "прячет". А перед этим ты для него создаешь таймер и вешаешь на него чтение. Ну, типа, ioc.wait_async(аргументы, факты, ...), ну и myconnect.read_async(ioc, блаблабла,...).
Ну и возвращаясь к асинхронности, обсуждаемой в статье, ты вместо того, чтобы просто крутить свой ioc.run() сразу вызываешь await myconnect.read_async(ioc, blablabla). И не нужен тебе ioc.run(). Смысл есть при вызове всех этих подготовительных функций, если хочется асинхронно сделать (не совсем ясно, зачем), а вот в цикле чтения как раз смысла делать это нет.
1. Если какая-то операция не требует участия текущего потока в выполнении инструкций - то она и не должна блокировать этот поток
2. C применением асинхронных точек вызова можно перестроить и единый синхронный поток выполнения так - что он будет разорван (для этого он выстраивается в конечный автомат - как вариант реализации) - который будет переключаться между его частями двигаясь синхронно по точкам асинхронных вызовов
3. Если в системе вообще нет многопоточности - то вся асинхронность не отличимая от синхронности!
Но в клиентских приложениях (и уж тем более в серверных) - есть, хотя бы вне контекстная многопоточность - значит от неё можно извлекать синхронную пользу - минимизируя блокировку основного (пусть даже единого) потока выполнения! Ну а уж если была бы полная многопоточность - то асинхронность тут дала бы именно эффективность управления этой многопоточностью!
А сейчас в 1С все эти асинхронные функции - только иллюзия - и синтаксический сахар над требованиями асинхронности со стороны внешней среды выполнения (браузеры - за которыми стоит многопоточность, вернее многозадачность конечного API). Всё тоже самое в 1С можно был бы сделать и без асинхронного синтаксического подхода!
Был бы хотя бы больший контроль над асинхронными процессами действительно, выполняющимися в другом потоке - вне 1С (ни над параллельно открытыми формами в 1С) - чтобы можно было более широко управлять "ожиданием" этого результата - уже было бы здорово! Те же синхронные вызовы отправляемые на другой сервер, или во внешнюю компоненту, или в многозадачную ОС.
Ну и просто контекстно-изолированные клиентские фоновые задания - тоже здорово было бы!
Кстати, виртуальная машина - это очень хорошая исполнительная среда для достижения квазимногопоточности. Когда код вообще можно делить по кускам выполнения не только в точках асинхронности - просто легко переключая контекст выполнения команд (безусловно - будут свои нюансы, которые будут требовать особого решения).
Можно было бы и изолированные потоки - хотя бы для разных контекстов - свои - развнернуть!
Но, сейчас всё сильно упирается в браузеры - там проблемы с организаций многопоточности! И 1С там не применяет виртуальную машину - код 1С там транслируется а JS - там хоть тоже есть VM - но она не многопоточная - но можно запустить несколько условно изолированных контекстов с VM.
Есть процессы, которые в фоне нужны именно на клиенте.
А так же есть процессы - которые можно было бы запустить в фоне на сервере - накладные расходы просто превышают весь выигрыш!
Аналогично в 1С так криво построено клиент-серверное взамодействие - что не будет эффективным универсальным решением и поднятие постоянно выполняющегося фонового процесса, со всем нужным постоянно хранимым контекстом (если он возможен будет на сервере), и взаимодействие с ним мелкими порциями!
Ну а всех уже за долбавшие фризы пользовательского интерфейса на код, выполняющийся в клиентском контексте или при клиент-серверном вызове, на всё время такого вызова, это что - нормально для XXI века?
Банальный пример - допустим - есть web-сервис (неважно какая технология), который готов предоставлять данные клиенту - и их надо динамически выводить в клиентском контексте, скажем, в форме списка - вот и попробуйте эффективно это сделать в клиенте 1С! А потом добавим условие - что длительное кеширование - не вариант - нужны данные, с актуальностью до минуты (а лучше до пары секунд). И поток этих данных может быть - тысячи, условно, строк в минуту!
А на HTML+JS такие задачи решают эффективно уже лет 20.
Не говоря уже про желание сделать какую-то анимацию в клиенте 1С, больше чем просто гифка!
Не говоря уже о просто банальном длительном вызове с клиента на другой сервер!
Скажите - сделайте фоновым заданием. Я посмотрю, что будет с кластером 1С когда его вот так тысячи клиентов нагрузят десятками фоновых заданий! Где больше половины будет на другие сервера!
Что быстрее кончится - ресурсы кластера или его лицензии?
Про то что, чтение файлов - у нас это прерогатива тоже сервера - я молчу - файлы мы таскаем туда-сюда через сеть! Очень эффективно - особенно через Интернет!
Не говоря уже про доступность самих источников данных, когда это не файлы. Вот - есть сетевой сервис - он доступен со стороны клиента - но не доступен со стороны сервера - который вообще в другой сети - и как быть? Или доступен - но токен авторизации активирован на стороне клиента! И хрен его активируешь сто стороны сервера!
А если надо с оборудованием на стороне клиента взаимодействовать? Тоже на сервер фоновым заданием предложите отправлять?
Это я промолчу ещё про контекст формы - который просто так взять и отправить в фоновое задание вообще нельзя! И некоторые функции самой 1С, доступ которых возможен только на клиенте или хотя бы в контексте формы!
Да и вообще - фоновые задания тонкого, веб и мобильного с клиента не создаются - от чего их применение усложняется!
Да и на сервере - фоновые задания - порой это тоже - очень тяжело - а вот асинхронность и параллельность - были бы куда кстати!
1С - это не для расчетов на клиенте. Тем более на JS все рассчитывается, имха, раз в сто быстрее, при том у 1С даже дебагер есть для джаваскрипта, встроенный в поле этого ХТМЛ.
Но выше я обозначил узкие места такого мышления!
Но, всё же, воркеры добавили - да - изолированы - но можно выкрутиться - коли надо!
Да и обещания и асинхронность в JS вроде бы как раз хорошо реализована!
Кстати, JS ранее был очень тормознутый. Это где-то c движка V8 (не 1С) его сильно ускорили!
А 1С вообще не печётся об оптимизации!
Сергей, халтура.
Вот, допустим, есть у тебя код какой-нить, который дважды два считает. Этот код выполняется на твоем процессоре, а не на сервере лунном. В итоге ты думаешь, что асинхронно он у тебя может несколько дважды два сразу считать, но нет - не может. Т.е. он каждые дважды два будет считать последовательно, даже если ты обернешь это в "асинх".
А теперь допустим второе - у тебя дважды два считает сервер лунный, но две секунды - это к Луне и обратно. Ты сделал запрос, он улетел через роутеры на лунный сервер, твой комп ничего не делает - ждет. И вот тут если ты синхронно сто запросов обработаешь, то как минимум на ожидание сигнала ты потратишь по две секунды с каждого запроса, что выльется в два на сто, т.е. двести секунд. Но если ты сделаешь это асинхронно, то ты создашь за некоторое мгновение сто запросов лунному серверу, не ожидая ответа. В стародревние времена у тебя был бы коллбэк, который для каждых из этих ста запросов сработал бы, и ты вынужден бы был обрабатывать это все отдельно, хотя на джавах и прочем есть лямбда, поэтому функцию можно прописать прям в вот здесь. Но асинхронность дает тебе положить все результаты асинхронных функций в массив, т.е. как-то так:
Для А = 1 ПО 100 Цикл
Ресурс = "/лунный.сервер.рф/"+А;
МассивОжиданий(Запрос.ПолучитьАсинх(Ресурс, Заголовки));
КонецЦикла;
Для Каждого Ответ ИЗ МассивОжиданий Цикл
РеальныйОтвет = Ждать Ответ;
РазобратьсяСОтветом(РеальныйОтвет);
КонецЦикла;P.S. Никак ссылку не получается нормально вставить. Инфостарт, что ты делаешь, с конкурентами борешься?
Есть у меня такая процедура
&НаКлиенте
Процедура Баланс()
элементы.ГиперсслкаКошелек.Заголовок = "Получение данных!";
Документ = Элементы.ДокументHTML.Документ;
//Объект.БалансКошелькаETH=АсинхронныеВызовы.БалансАсинхронно(Документ);
Документ.defaultView.Check_balance();
БалансКошелькаETH = Документ.defaultView.async_balance();
Если БалансКошелькаETH="Nll" тогда
ПодключитьОбработчикОжидания("Баланс",1);
иначе
объект.БалансКошелькаETH=БалансКошелькаETH;
ОтключитьОбработчикОжидания("Баланс");
элементы.ГиперсслкаКошелек.Заголовок = Документ.defaultView.GetWallet();
Документ.defaultView.return_OK()
КонецЕсли;
КонецПроцедуры ПоказатьВ свою очередь имеется асихронный вызов функции JavaScript
async function Check_balance() {
let balancePromise = wallet.getBalance();
balancePromise.then((balance) => {
let parsed_balance = ethers.utils.formatEther(balance);
window.balance = parsed_balance;
document.write(JSON.stringify(balance))
return parsed_balance;
Так вот я не смогу добиться асихронного вызова функции:
Объект.БалансКошелькаETH=АсинхронныеВызовы.БалансАсинхронно(Документ); Пришлось делать через
ПодключитьОбработчикОжидания("Баланс",1) Я понимаю так:
1.
...
Диалог = Новый ДиалогВыбораФайлов(Режим);
Если Диалог.Выбрать() Тогда
ИмяФайла = Диалог.ПолноеИмяФайла;
... ОБРАБОТКА ФАЙЛА ...
КонецЕсли;2.
...
Диалог = Новый ДиалогВыбораФайлов(Режим);
Диалог.Показать(Новый ОписаниеОповещения("ПриВыбореФайла", "ЭтаФорма", ДополнительныеПараметры));
// ЭТОТ КОД ПРИВЕДЕТ НАС В ПРОЦЕДУРУ "ПриВыбореФайла"
...
&НаКлиенте
Процедура ПриВыбореФайла(Результат, ДополнительныеПараметры) Экспорт
Если ЗначениеЗаполнено(Результат) Тогда
ИмяФайла = Результат[0];
... ОБРАБОТКА ФАЙЛА ...
КонецЕсли;
КонецПроцедуры
Показать3.
... где тот код, который приведет в асинхронную процедуру ?
&НаКлиенте
Асинх Процедура ВыбратьИмяФайла(Команда)
Диалог = Новый ДиалогВыбораФайлов(Режим);
Результат = Ждать Диалог.ВыбратьАсинх();
Если ЗначениеЗаполнено(Результат) Тогда
ИмяФайла = Результат[0];
КонецЕсли;
КонецПроцедуры ПоказатьЗЫ: Сдается мне, что Вы слишком переоцениваете асинхронность вообще. Она - это тот самый выход из того самого ада коллбэков, в который попадают плохие программисты. Все, больше она ни для чего не нужна.
Результат = Ждать Диалог.ВыбратьАсинх();Обещание = Диалог.ВыбратьАсинх(); // открыли диалог
Результат = Ждать Обещание; // ждем, пока в нем что-то нажмут, в переменной "Результат" то, что там нажали.Собственно претензия моя состоит в том, что правильно было бы так написать:
1. Модальный код:
&НаКлиенте
Процедура ВыбратьИмяФайла(Команда)
Диалог = Новый ДиалогВыбораФайлов(Режим);
Если Диалог.Выбрать() Тогда
ИмяФайла = Диалог.ПолноеИмяФайла;
КонецЕсли;
КонецПроцедуры
2. Код с описанием оповещения:
&НаКлиенте
Процедура ВыбратьИмяФайла(Команда)
Диалог = Новый ДиалогВыбораФайлов(Режим);
Диалог.Показать(Новый ОписаниеОповещения("ПриВыбореФайла", "ЭтаФорма", ДополнительныеПараметры));
КонецПроцедуры
...
&НаКлиенте
Процедура ПриВыбореФайла(Результат, ДополнительныеПараметры) Экспорт
Если ЗначениеЗаполнено(Результат) Тогда
ИмяФайла = Результат[0];
КонецЕсли;
КонецПроцедуры
Код увеличился, появилась еще одна процедура. Благо, что ее можно было засунуть хоть в общий модуль и вообще сделать одну процедуру на все случаи жизни.
3. Асинхронно:
&НаКлиенте
Асинх Процедура ВыбратьИмяФайла(Команда)
Диалог = Новый ДиалогВыбораФайлов(Режим);
Результат = Ждать Диалог.ВыбратьАсинх();
Если ЗначениеЗаполнено(Результат) Тогда
ИмяФайла = Результат[0];
КонецЕсли;
КонецПроцедуры
Практически вернулись к привычной модальной записи, но имеем асинхронность, которую требует современное программное окружение 1С, вроде браузеров.
Как по мне, технология Асинх введена в 1С всё же для любителей синхронно выглядящего кода. И чтобы было модно, "как в C#".
Ошибку пишет:
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(12,10)}: Оператор Ждать (Await) может употребляться только в асинхронных процедурах или функциях
Ответ = <<?>>Ждать Диалог .ВыбратьАсинх();
А нужно слово асинх фпереди писать...
Слона не заметил...
Синтакс фуфельный, хоть бы написали по человечьи...
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 1746248
Создание 23.10.22 21:30
Обновление 23.10.22 21:30
Просмотры 14684
Загрузки 0
Рейтинг
49
Комментарии 58
Код открыт Да
Рубрики Механизмы платформы 1С
Кому Разработчик
Тип файла Нет файла
Платформа 1С:Предприятие 8
Конфигурация Универсальные
Операционная система Не имеет значения
Страна Не имеет значения
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)