Семеро одного не ждут? Асинхронное исследование асинхронности

08.06.21

Разработка - Механизмы платформы 1С

Все уже, наверное, знают о появлении в новых версиях платформы асинхронных функций и конструкций Асинх/Ждать. Многие, возможно, уже их используют. Но что будет, если создать свои асинхронные функции, запустить и не дожидаться окончания их выполнения? Неужели можно запустить несколько процессов параллельно?

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Асинхронное исследование асинхронности
.epf 8,23Kb
3
3 Скачать (1 SM) Купить за 1 850 руб.

Появление долгожданного средства, аналогичного Async/Await в других языках, дало возможность существенно улучшить написание кода.

 

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

 

Эксперимент 1. Собственные асинхронные функции

Создадим 4 асинхронных функции, так, чтобы они вызывались каскадно:

Эксперимент1(Команда) // Функция0
    - Функция1()
        - Функция2()
            - Функция3()
                - Функция4()

Вызов каждой функции сделаем опционально: с ключевым словом Ждать и без него (в зависимости от соответствующего флажка). Будем фиксировать время, прошедшее от старта эксперимента, в следующих точках: начало выполнения функции (оно же вызов вложенной функции), начало выполнения кода после вызова вложенной функции и завершение выполнения. Тело функции - простая задержка на определенное количество секунд. Для наших функций выберем задержки 1, 2, 4, 8, 16. Надеюсь, всем понятно, почему выбран ряд степеней двойки?:) Код получившихся функций имеет вид:

&НаКлиенте
Асинх Функция Функция1()
	ДобавитьВЛог("Функция1: Старт");
	Если Ждать2 Тогда   
		Ответ2 = Ждать Функция2();
	Иначе
		Ответ2 = Функция2();
	КонецЕсли;   	
	ДобавитьВЛог("Функция1: После вызова Функция2");	
	Задержка(2);	
	ДобавитьВЛог("Функция1: Финиш");
	Возврат 1;
КонецФункции 

Результаты будем выводить в список значений на форме. Почему не в окно сообщений? Потому что, как показал эксперимент, при работе асинхронных функций порядок вывода сообщений с помощью Сообщить() не соответствует ожидаемому. Дополнительно выведем на форму значения переменных ОтветN - результатов возврата соответствующих функций ФункцияN. Кроме этого создадим обработчик ожидания, который каждую секунду будет выводить на форму текущее время.

Итак, начнем.

 

Эксперимент 1.1

Запустим наши асинхронные функции без использования Ждать

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

Через полминуты получим результат:

Функция0: Старт :: 0сек.
Функция1: Старт :: 0сек.
Функция2: Старт :: 0сек.
Функция3: Старт :: 0сек.
Функция4: Старт :: 0сек.
Функция4: Финиш :: 16сек.
Функция3: После вызова Функция4 :: 16сек.
Функция3: Финиш :: 24сек.
Функция2: После вызова Функция3 :: 24сек.
Функция2: Финиш :: 28сек.
Функция1: После вызова Функция2 :: 28сек.
Функция1: Финиш :: 30сек.
Функция0: После вызова Функция1 :: 30сек.
Функция0: Финиш :: 31сек.

Ответ1: Обещание	
Ответ2: Обещание
Ответ3: Обещание
Ответ4: Обещание

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

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

 

Эксперимент 1.2

Сделаем теперь вызов Функция3 с помощью Ждать

Результат:

Функция1: Старт :: 0сек.
Функция2: Старт :: 0сек.
Функция3: Старт :: 0сек.
Функция4: Старт :: 0сек.
Функция4: Финиш :: 16сек.
Функция3: После вызова Функция4 :: 16сек.
Функция3: Финиш :: 24сек.
Функция1: После вызова Функция2 :: 24сек.
Функция1: Финиш :: 26сек.
Функция0: После вызова Функция1 :: 26сек.
Функция0: Финиш :: 27сек.
Функция2: После вызова Функция3 :: 27сек.
Функция2: Финиш :: 31сек.
Функция0: Старт :: 0сек.

Ответ1: Обещание	
Ответ2: Обещание
Ответ3: 1
Ответ4: Обещание

Что мы видим: после старта Функции2, запускается Функция3 и Функция4, они полностью отрабатывают, после этого работа Функции2 прерывается (несмотря на то что Функция3 полностью завершилась и результат уже готов), управление передается Функции1. Функция2 заканчивает свою работу после окончании работы всех вышестоящих функций. На первый взгляд выглядит это довольно странно, хотя определенная логика в этом есть: Ждать применяется не к функции, а к результату функции, т.е. вместо

Ответ3 = Ждать Функция3();

можно написать

Результат = Функция3();
Ответ3 = Ждать Результат;

и тогда становится понятно, почему Функция3 выполняется полностью.

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

 

Эксперимент 1.3

Добавим теперь Ждать к вызову Функции2 и Функции4

и получим результат:

Функция0: Старт :: 0сек.
Функция1: Старт :: 0сек.
Функция2: Старт :: 0сек.
Функция3: Старт :: 0сек.
Функция4: Старт :: 0сек.
Функция4: Финиш :: 16сек.
Функция2: После вызова Функция3 :: 16сек.
Функция2: Финиш :: 20сек.
Функция0: После вызова Функция1 :: 20сек.
Функция0: Финиш :: 21сек.
Функция3: После вызова Функция4 :: 21сек.
Функция3: Финиш :: 29сек.
Функция1: После вызова Функция2 :: 29сек.
Функция1: Финиш :: 31сек.

Ответ1: Обещание	
Ответ2: 1
Ответ3: Обещание
Ответ4: 1

Как видим, отработала Функция4, Функция3 приостановилась после возврата из Функции4, завершилась Функция2, Функция1 приостановилась после возврата из Функции2, завершился обработчик нажатия кнопки. После этого продолжилось выполнение Функции3 и Функции1. Так же, как и в предыдущих случаях блокировался пользовательский интерфейс и не выполнялся обработчик ожидания.

Вывод: При каскадном выполнении все функции, содержащие Ждать, приостанавливают свою работу, пока не выполнятся все вышестоящие функции. Приостановленное выполнение продолжится в том же порядке, в котором было остановлено.

Итоговый вывод: Использование собственных асинхронных функций (без асинхронных функций платформы) выглядит нецелесообразным. Единственный эффект, которого можем достичь, - изменение порядка выполнения кода, что приносит мало пользы, но может затруднить понимание кода и его отладку.

Идем дальше. Может с применением платформенных асинхронных функций будет получше?

 

Эксперимент 2. Интерактивные функции платформы

На замену функциям модального режима(напр. Предупреждение) и функциям немодального режима (напр. ПоказатьПредупреждение) пришли асинхронные функции (напр. ПредупреждениеАсинх). Для обеспечения взаимодействия с пользователем кроме ПредупреждениеАсинх появились также ВопросАсинх и ОткрытьЗначениеАсинх. Проведем эксперимент №2.

&НаКлиенте
Процедура Эксперимент2(Команда)
	НачалоЭксперимента();
	ДобавитьВЛог("Проц: Старт");
	ИнтерактивныеФункции();
	ДобавитьВЛог("Проц: После вызова ИнтерактивныеФункции");	
	ЗапускОжиданияОтвета(1);
	ЗапускОжиданияОтвета(2);
	ЗапускОжиданияОтвета(3);	
	ДобавитьВЛог("Проц: Финиш");
КонецПроцедуры

&НаКлиенте
Асинх Процедура ИнтерактивныеФункции()
	ДатаСтарта = ТекущаяДата();
	ДобавитьВЛог("ИнтерактивныеФункции: Старт");
	Ответ1 = ПредупреждениеАсинх("Предупреждение 1");
	ДобавитьВЛог("ИнтерактивныеФункции: После вызова ПредупреждениеАсинх");
	Ответ2 = ОткрытьЗначениеАсинх("Значение 2");
	ДобавитьВЛог("ИнтерактивныеФункции: После вызова ОткрытьЗначениеАсинх");
	Ответ3 = ВопросАсинх("Вопрос 3", РежимДиалогаВопрос.ДаНет);
	ДобавитьВЛог("ИнтерактивныеФункции: После вызова ВопросАсинх");		
	ДобавитьВЛог("ИнтерактивныеФункции: Финиш");
КонецПроцедуры

&НаКлиенте
Асинх Процедура ЗапускОжиданияОтвета(Номер)
	ДобавитьВЛог("ЗапускОжиданияОтвета " + Номер + ": Старт");
	Если 	  Номер = 1 Тогда   Ответ1 = Ждать Ответ1;
	ИначеЕсли Номер = 2 Тогда   Ответ2 = Ждать Ответ2;
	ИначеЕсли Номер = 3 Тогда   Ответ3 = Ждать Ответ3;
	ИначеЕсли Номер = 4 Тогда   Ответ4 = Ждать Ответ4;	
	КонецЕсли; 
	ДобавитьВЛог("ЗапускОжиданияОтвета " + Номер + ": Финиш");
КонецПроцедуры

Код выше последовательно выполняет ПредупреждениеАсинхОткрытьЗначениеАсинх и ВопросАсинх. После этого запускается ожидание результата каждого вызова. 

Результат на экране:

 

 

Наконец-то, в отличие от первого эксперимента, получилось что-то похожее на параллельность: запустились все 3 асинхронные функции без каких-либо задержек между ними, и (главное!) для каждой запустили независимое ожидание ответа. Пока система ждет реакции пользователя, каждую секунду отрабатывает обработчик ожидания, т.е. "параллельно" с раздумьями пользователя может выполняться какой-либо код. Пока пользователь не дал свой ответ, все результаты функций - Обещание.

Последовательно закроем все диалоговые окна и получим:

 

 

Обещание каждой функции превратилось в какое-либо значение. Каждая процедура ЗапускОжиданияОтвета завершилась отдельно от других — то есть система сохраняла контекст каждой функции до тех пор, пока пользователь не сделал свой выбор. К сожалению, каждое диалоговое окно блокировало интерфейс, включая предыдущие диалоговые окна, поэтому а) нельзя посмотреть, что будет, если закрывать окна в произвольном порядке, б) IRL для пользователя процесс будет выглядеть последовательным: последовательно открылись диалоговые окна, в обратном порядке их последовательно закрыли.

Вывод: Использование асинхронных интерактивных функций позволяет распараллелить как минимум два процесса: ожидание реакции пользователя на диалоговое окно и выполнение кода в обработчике (обработчиках) ожидания.  При этом сохраняется возможность получить и обработать ответ пользователя. Так как диалоговые окна блокируют остальной интерфейс, то пользователь не может совершать другие действия во время ожидания.

С интерактивными функциями все понятно, а что с файловыми?

 

Эксперимент 3. Функции работы с файлами

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

&НаКлиенте
Асинх Процедура Эксперимент3(Команда)
	НачалоЭксперимента();
	ДобавитьВЛог("Эксперимент 3: Старт");
	ФайловыеФункции();
	ДобавитьВЛог("Эксперимент 3: После вызова ФайловыеФункции");
	ЗапускОжиданияОтвета(1);
	ЗапускОжиданияОтвета(2);
	ДобавитьВЛог("Эксперимент 3: Финиш");
КонецПроцедуры

&НаКлиенте
Асинх Процедура ФайловыеФункции()
	НачалоЭксперимента();
	ДобавитьВЛог("ФайловыеФункции: Старт");
	Ответ1 = КопироватьФайлАсинх("D:\1\BigFile1", "D:\1\BigFile1Copy");
	ДобавитьВЛог("ФайловыеФункции: После вызова копирования 1");
	Ответ2 = КопироватьФайлАсинх("D:\1\BigFile2", "D:\1\BigFile2Copy");
	ДобавитьВЛог("ФайловыеФункции: После вызова копирования 2");
	ДобавитьВЛог("ФайловыеФункции: Финиш");
КонецПроцедуры

В третьем эксперименте сделаем программно копии файлов BigFile1 (размер ~4,2 Гб) и BigFile2 (размер ~1,4 Гб).

Запускаем тест и... на несколько минут вся система замирает: недоступен интерфейс, ничего не отражается в логе, не запускается обработчик ожидания.

Только спустя некоторое время мы видим:

 

 

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

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

Может передача файлов на сервер будет работать лучше?

 

Эксперимент 4. Функции обмена файлами с сервером

&НаКлиенте
Процедура Эксперимент4(Команда)
	НачалоЭксперимента();
	ДобавитьВЛог("Эксперимент 4: Старт");
	ФайловыеФункции2();
	ДобавитьВЛог("Эксперимент 4: После вызова ФайловыеФункции2");
	ЗапускОжиданияОтвета(1);
	ЗапускОжиданияОтвета(2);
	ДобавитьВЛог("Эксперимент 4: Финиш");
КонецПроцедуры

&НаКлиенте
Асинх Процедура ФайловыеФункции2()
	НачалоЭксперимента();
	ДобавитьВЛог("ФайловыеФункции2: Старт");
	Ответ1 = ПоместитьФайлНаСерверАсинх(,,, "D:\1\File1");
	ДобавитьВЛог("ФайловыеФункции2: После вызова помещения файла 1");
	Ответ2 = ПоместитьФайлНаСерверАсинх(,,, "D:\1\File2");
	ДобавитьВЛог("ФайловыеФункции2: После вызова помещения файла 2");
	ДобавитьВЛог("ФайловыеФункции2: Финиш");
КонецПроцедуры

Здесь мы помещаем на сервер File1 (размер 56 Мб) и File2 (размер 23 Мб).

Итак запускаем...

Бинго! Все работает так, как нам бы хотелось:

Сразу после запуска:

 

 

через несколько секунд:

 

 

и в конце:

 

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

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

На этом наши эксперименты завершены. Все эксперименты проводились в клиент-серверном режиме, в тонком клиенте, на платформе 8.3.18.1363. В следующих версиях поведение платформы может измениться. За рамками исследования остался веб-клиент, функции вроде ПодключитьРасширениеРаботыСФайламиАсинхЗапуститьПриложениеАсинх и т.п., асинхронные методы объектов МенеджерФайловыхПотоковТабличныйДокумент и других. Желающие могут продолжить эксперименты самостоятельно, обработка приложена к статье.

Хотелось бы отметить, что несмотря на все преимущества методики Асинх/Ждать не стоит отказываться от функций, использующих ОписаниеОповещения. В ряде случаев применение ОписаниеОповещения предпочтительнее. Во-первых: когда различные исходы функции требуют различной обработки и/или в процессе выполнения надо дать возможность вызывать пользовательский код - можно передать в параметрах несколько обработчиков. Для примера можно привести функцию ПоместитьФайлНаСерверАсинх(<ОписаниеОповещенияОХодеВыполнения>, <ОписаниеОповещенияПередНачалом>, <Адрес>, <ПутьКФайлу>, <УникальныйИдентификаторФормы>). Здесь совмещены оба подхода - Асинх/Ждать и  ОписаниеОповещения. Во-вторых: ОписаниеОповещения можно передать параметром внутрь каскада выполняющихся функций, для того, чтобы какая-то из них (а может и не одна), имела возможность вернуть свой результат в вызывающий модуль. Тем самым это напоминает передачу указателя на функцию в некоторых языках. Преимуществом же Асинх/Ждать является большая наглядность, сокращение объема кода и полный доступ к контексту выполнения вызывающего кода после завершения асинхронной функции (напомню, что при использовании ОписаниеОповещения необходимый контекст надо передать в ДополнительныеПараметры).

И напоследок, пара ложек дегтя. Первая ложка: отсутствует функция ОткрытьФормуАсинх. В моих проектах бОльшая часть случаев использования ОписаниеОповещения относится к открытию форм и обработке результатов закрытия. Вторая ложка: почему нельзя определить, что находится внутри Обещание без использования Ждать? Ведь Ждать вызывает приостановку выполнения кода, а это может быть вовсе не нужно. Надеемся, в будущем это будет доработано.

PS: Как всегда, в комментариях приветствуются замечания, дополнения и сообщения об ошибках. 

PPS: А что же все-таки значит в заголовке "... Асинхронное исследование ..."?

 

 

Асинх Асинхронные функции Ждать Обещание Async Await Promise

См. также

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Эта небольшая статья - некоторого рода шпаргалка по файловым потокам: как и зачем с ними работать, какие преимущества это дает.

23.06.2024    7505    bayselonarrend    20    

154

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    5962    dsdred    16    

80

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    17786    YA_418728146    26    

71

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    23783    SeiOkami    48    

135

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

28.08.2023    14774    YA_418728146    7    

166
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. alexey_kurdyukov 165 08.06.21 06:53 Сейчас в теме
Тот вариант, когда Асинх методы вызываются в не Асинх функции, а она в свою очередь тоже откуда-то вызывается у меня как-то раз завершился тем, что вывалилась пара сотен вопросов, после чего упала даже не платформа, а винда в синий экран. Так что, я бы использовал это вот всё с осторожностью.
TimkoNzt; bulpi; +2 Ответить
2. tormozit 7230 08.06.21 07:21 Сейчас в теме
В обычном приложении Сообщить() работает синхронно. Можно было бы не городить свой буфер сообщений.
DrAku1a; sinichenko_alex; +2 Ответить
3. Alxby 1113 08.06.21 10:30 Сейчас в теме
(2) В управляемом приложении для эксперимента 1.3 логирование с помощью Сообщить() дает вот такой результат:
Функция1: Финиш :: 31сек.
Функция3: Финиш :: 29сек.
Функция0: Финиш :: 21сек.
Функция0: После вызова Функция1 :: 20сек.
Функция2: Финиш :: 20сек.
Функция2: После вызова Функция3 :: 16сек.
Функция4: Финиш :: 16сек.
Функция4: Старт :: 0сек.
Функция3: Старт :: 0сек.
Функция2: Старт :: 0сек.
Функция1: Старт :: 0сек.
Функция0: Старт :: 0сек.
Функция1: После вызова Функция2 :: 29сек.
Функция3: После вызова Функция4 :: 21сек.

А в обычном, да, работает нормально, более того, сообщения в окне сообщений появляются в процессе, а не по завершению эксперимента.
5. tormozit 7230 08.06.21 15:17 Сейчас в теме
(3)
более того, сообщения в окне сообщений появляются в процессе

Ну в общем то это и называется "синхронно". Конечно еще можно было бы трактовать как синхронный вывод в буфер с асинхронным отображением, но это кажется лишено смысла для вывода оперативной информации, которой обычно являются сообщения пользователю. Хотя при большом потоке сообщений асинхронное (например раз в секунду) отображение станет вполне актуальным.
Il; sinichenko_alex; +2 Ответить
7. Alxby 1113 08.06.21 15:35 Сейчас в теме
(5)Так я с этим и не спорю:). Я лишь хочу уточнить, что в управляемом приложении не сохраняется порядок вывода сообщений. Кстати, можно попробовать СообщениеПользователю, вполне возможно там будет другой эффект
10. Yashazz 4791 08.06.21 22:01 Сейчас в теме
(7) поэкспериментируйте с ПолучитьСообщенияПользователю, там тоже могут ждать прелюбопытные сюрпризы - и в составе результата, и в порядке его элементов.
sinichenko_alex; +1 Ответить
9. Yashazz 4791 08.06.21 21:59 Сейчас в теме
(2) Можно было вообще и просто писать в ЖР)
12. Alxby 1113 08.06.21 22:14 Сейчас в теме
(9)Можно, но ЖР анализировать менее удобно
28. kalyaka 1105 10.06.21 10:10 Сейчас в теме
(2)Поясните, пожалуйста, почему при исполнении следующего кода порядок сообщений в тонком клиенте один, а в браузере Chrome другой?
Ответ представителя 1С: "порядок появления сообщений в тонком клиенте не соответствует порядку выполнения вызовов метода Сообщить().
По этому поводу зарегистрирована ошибка.
"
&НаКлиенте
Асинх Процедура ВыполнитьАсинхронно()
   Ждать 1;
   Сообщить("Начало асинхронного выполнения");
КонецПроцедуры

&НаКлиенте
Процедура КомандаВыполнить(Команда)
   Сообщить("Начало синхронного кода");
    ВыполнитьАсинхронно();
   Сообщить("Завершение синхронного кода");
КонецПроцедуры
Показать
Тонкий клиент:

Начало асинхронного выполнения
Начало синхронного кода
Завершение синхронного кода

Chrome:

Начало синхронного кода
Завершение синхронного кода
Начало асинхронного выполнения
4. 7OH 70 08.06.21 15:11 Сейчас в теме
"В следующих версиях поведение платформы может измениться."
А в истории такие случаи разве были хоть раз ?
Фраза "Нет ничего более постоянного, чем временное" - это 100% про 1С
---
Кстати тоже проводит эксперименты похожие.
Через свой "буфер" вывода и через сообщить порядок вывода был неожиданно разным в последовательности.
sinichenko_alex; +1 Ответить
6. Alxby 1113 08.06.21 15:21 Сейчас в теме
(4)Я исхожу из того, что все, что не описано в документации, разработчики платформы вправе поменять без какого-либо уведомления. Вполне возможно, что в новых версиях эти эксперименты будут давать немного другой результат, при сохранении в целом описанного функционала, например копирование файлов будет многопоточно-параллельно.
8. starik-2005 3088 08.06.21 18:27 Сейчас в теме
Да, собственные "асинхронные" функции ни разу не асинхронны. Печалька.
d4rkmesa; Sergey_Borisovi4; ivanov660; Yashazz; +4 Ответить
11. Yashazz 4791 08.06.21 22:03 Сейчас в теме
Автор, не обижайтесь, но подобные исследования это на 90% пустая трата времени. Вот когда устаканится, уложится, релизов 3-4 пройдёт, тогда будет иметь смысл копать.
SuperSpade; +1 Ответить
13. Alxby 1113 08.06.21 22:19 Сейчас в теме
(11)Какие обиды? Исследование родилось не на пустом месте, а из вполне практических задач. Времени с момента появления этого функционала прошло вполне достаточно, чтобы большинство "детских болезней" были исправлены, так что на мой взгляд исследование вполне своевременно.
user598655_ilia-bers; +1 Ответить
14. anosin 29 08.06.21 23:15 Сейчас в теме
(13) интересна предметная область таких практических задач. Можно на пальцах пояснить про задачи?
15. Alxby 1113 09.06.21 15:30 Сейчас в теме
(14)да ничего особенного. В рамках глубокого рефакторинга кода понадобилось выяснить особенности работы и границы применимости этого механизма
17. Darklight 33 09.06.21 16:22 Сейчас в теме
(11)Вы не правы. Исследования нужны и в самом начале - что бы люди сразу знали - "что по чём" и не строили иллюзий по поводу крутости новой функциональности
18. Yashazz 4791 09.06.21 18:07 Сейчас в теме
(17) Соглашусь. Да, кто-то должен быть первопроходцем. Но я ведь говорю о ценности этой публикации, где не грабли собраны и не баги описаны, а проведено исследование с целью подтверждения некоторой гипотезы.
24. Darklight 33 10.06.21 09:20 Сейчас в теме
(18)В статье людям показали на что можно сейчас рассчитывать. На что пока не стоит. Как пользоваться, как работает. Да, исследование далеко не полное - и это снижает его ценность, но она всё-равно есть; и даже просто почитать людям будет интересно, даже если пользоваться этим они и не собирались
16. Darklight 33 09.06.21 16:13 Сейчас в теме
Теперь у хейтеров будет меньше поводов считать язык 1С недоязыком:)

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

Главное назначение асинхронных функций в статье не раскрыто - а лишь дано поверхностное описание в конце - без чётких примеров и пояснения назначения - а именно:

Они хороши именно при работе со встроенными асинхронными функциями 1С (чаще всего интерактивными, или для файловых операций) - чтобы не дробить текст алгоритма на кучу функций-продолжений, которые используются вместе с "ОписаниеОповещения", передавая весь контекст (о как я намучился когда-то с последовательным поиском каталогов и файлов - с промежуточной обработкой результата - и это у меня ещё не было там интерактивной работы - только один последовательный алгоритм; особо помучился с циклическими поиском - ведь если на найдено, скажем, несколько каталога - то каждый из них нужно обработать отдельно - выполним в там свой поиск и ещё раз и ещё раз во вложении... и это я ещё чтение/запись файлов не стал делать асинхронным - просто не требовалось для без модальности).
Вот такие Асинх/Ждать мне бы позволили разместить весь алгоритм в одной двух асинхронных функциях.

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

Я, например, очень жду асинхронных методов для объекта "HTTPСоединение" (а других - для внешних вызовов), и надеюсь, что они не будут именно параллельные - что можно запустить сразу несколько обращений и потом получить их результаты (в идеале просто ожидая их по массиву Обещаний - кто первый выполнится - чтобы сразу обработать и ждать остальных так же последовательно).

Для работы с Фоновыми заданиями асинхронность тоже не помешала бы - но пока нету!

Автор не рассмотрел ещё одну важную тему экспериментов - асинхронные клиент-серверные вызовы. Интересно что с этим? Конечно ждать настоящей асинхронности (не параллельной) таких вызовов от 1С просто глупо! Но хотя бы какой-нибудь....
А ну да - асинхронных функций на сервере вообще нет, так что их нельзя даже с клиента запустить. Об этом стоило бы упомянуть!
И это ещё один повод хейтить 1С Предприятие 8 - ведь в других платформах асинхронные вызовы в серверном и клиент-серверном контексте - это основа всех современных алгоритмов обработки данных и клиент-серверного взаимодействия!

Автору - жаль, что Вы сэкономили пространство и не привели текст всех функций теста (хоть они и однотипны но это усложняешь восприятие статьи). Приведите хотя бы функцию "Функция4" - она же отлична от остальных

Но за статью всё равно + :-)

P.S
Кстати, интересно, для применения конструкций Асинх/Ждать нужна только платформа не моложе 8.3.18 - или нужно ещё и совместимость с 8.3.18 ставить в конфигурации? Если нужна совместимость - то толку от этой асинхронности сейчас совсем совсем мало. А к тому моменту, когда к этому режиму совместимости подтянутся типовые, и тем более, когда они начнут это активно использовать внутри конфигураций - вот тогда и смысл в применении будет, да и глюков будет поменьше, а возможностей побольше - хотя бы на йоту!

P.P.S
Интересно - а что там на выходе в байткоде... на неуправляемом приложении вроде бы можно получить для клиентского контекста. Как они это реализовали - всё на старых опКодах или новые ввели?
antonio_i; silberRus; Il; info1i; Yashazz; +5 Ответить
20. Alxby 1113 09.06.21 20:20 Сейчас в теме
(16)Отвечу по порядку. Действительно, в статье не описано подробно назначение и применение этого механизма. С одной стороны не хотелось загромождать публикацию, а с другой - по моему мнению, не стоит дублировать синтаксис-помощник и методические рекомендации от 1С - там это в нужном объеме описано (даже если "...документацию никто не читает"). Асинхронные функции и объект Обещание доступны только на клиенте, поэтому говорить о фоновых заданиях и клиент-серверных вызовах смысла не имеет (возможно что только пока). Функция4() содержит то же что и остальные, только без вызова подчиненной, так как она последняя. Для желающих весь код - в приложенной обработке, если есть проблемы со стартмани, могу выслать в личку. Конечно совместимость с 8.3.18 ставить не нужно, 1С обычно не ломает функционал в последующих версиях платформы, но чисто теоретически поведение может измениться - например функции станут работать параллельно - но ведь это же хорошо, верно? А по поводу байт-кода - см. https://www.youtube.com/watch?v=vt1aoPXx9fY. Там же более подробно рассказано и о механизме, и о применении асинхронных вызовов.
25. Darklight 33 10.06.21 09:39 Сейчас в теме
(20)Документация это хорошо, но многие ли её читают? А те кто читают, многие ли понимают всю суть? Документацию 1С пишет из рук вон плохо далеко не всегда особо содержательно и понятно, читается она, обычно, достаточно тяжело (сейчас говорю про документацию к платформе), а встроенная справка и синтаксис помощник - это вообще жесть (синтаксис помощник ругать не хочу - обычно со своей работой задачей он справляется, но это не совсем документация, по которой нужно изучать функционал, хотя отчасти можно). Да даже, если взять техническую документацию, которую пишет Микрософт, которая спроектирована достаточно хорошо (ну за десятилетия и нехилые вложения средств в юзерфрендли они научились, хотя бы техничку писать хорошо). То и тут, люди пишут пишут всякие статьи о новых фишках, исследования и т.п. - повторяя, проверяя и разжёвывая то, что достаточно чётко (но не всегда полно и понятно) написано в оф. документации. Даже есть сайты, которые пишут полностью свою, независимую (пусть и ограниченную) документацию - так как имеют своё виденье правильности подачи материала (ну и хотят заработать на рекламе). Дословно цитировать документацию не нужно. Нужно разъяснять своими словами, подкрепляя примерами конкретных исследований, привнося свой взгляд на вещи, давая свои собственные рекомендации по использованию, расставляя свои акценты. А то документации может написано одно (эффективные маркетологи и сюда уже добрались), а на деле - совсем другое!

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

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

За видео спасибо
22. Perfolenta 206 09.06.21 22:53 Сейчас в теме
(16)
асинхронных функций на сервере вообще нет

могу конечно ошибаться, но как мне кажется, для клиента они транслируют код 1С в JavaScript, а там есть похожая асинхронность...
а на сервере работает интерпретатор 1С и у него нет реализации асинхронности...
23. kalyaka 1105 10.06.21 08:56 Сейчас в теме
(22) на веб-клиенте все транслируется в javascript и 1С не исключение. Javascript - это байт-код для веба, движек JS - виртуальная машина исполнения в браузерах
26. Darklight 33 10.06.21 09:40 Сейчас в теме
(22)JavaScript в 1С есть только в WEB-Клиенте. Но есть ещё Тонкий и Толстый клиенты , и вообще - неуправляемое приложение
27. kalyaka 1105 10.06.21 09:55 Сейчас в теме
(26)
И тонкий клиент (при работе через веб), и веб-клиент пользуются одним и тем же набором веб-сервисов для общения с сервером приложений 1С. Реализация у клиентов, конечно, разная – тонкий клиент написан на С++, веб-клиент – на JavaScript.
Про веб-клиент 1С
29. Darklight 33 10.06.21 11:34 Сейчас в теме
(27)К чему Вы это. Речь шла только про выполнение асинхронного кода на стороне клиента
30. kalyaka 1105 10.06.21 11:39 Сейчас в теме
(29) к тому что на всех клиентах по идее все должно быть одинаково реализовано. Для web клиента просто функциональность оттранслирована в JS. Для серверной части своя, отличная от клиентской части реализация платформы и в ней нету асинхронности.
31. Darklight 33 10.06.21 11:39 Сейчас в теме
(21)
Для web клиента просто функциональность оттранслирована в JS

Уже можно считать, что не одинаково
32. kalyaka 1105 10.06.21 12:10 Сейчас в теме
(31) ну на уровне стековой машины логика должна быть одинакова
34. Darklight 33 10.06.21 14:53 Сейчас в теме
(32)А я всё надеялся что на WEB-клиенте весь код 1С преобразуется код в JavaScript без стековой машины
36. kalyaka 1105 10.06.21 15:32 Сейчас в теме
(34) ну это не точно. Однако почему то оператор Выполнить в веб-клиенте не поддерживается, а вот Вычислить - да.
Наверно все-таки стековая машина порождает код на JS, тогда логично. В JS же выполнить код нельзя, а вот вычислить (eval) - можно.
37. Darklight 33 10.06.21 15:51 Сейчас в теме
(36)Зачем там вообще стековая машина! Когда весь код 1С модно транслировать в код "JavaScript". Вон язык "Kotlin" транслирует в JS куда более сложный код!
"JavaScript" - Это интерпретируемый язык. Тут нельзя получить примитивные инструкции из примитивных (стековая машина) и примитивно их отправить на выполнение. Весь вызываемый алгоритм должен быть полностью детерминирован
38. kalyaka 1105 10.06.21 15:59 Сейчас в теме
(37) ну я предполагаю, что стековая машина на сервере не исполняет код, а транслирует в JS для клиента. Т.е. получается такой транспайлер из 1С в JS. Возможно правильнее здесь использовать термин компилятор в JS.
А если бы стековую машину тащить на клиента, то и байткод на 1С тоже тогда туда надо тащить. Код веб-клиента то открыт, может кто и расковыряет как оно там на вебе :)
39. Darklight 33 10.06.21 17:02 Сейчас в теме
(38)Я думаю, что на WEB-клиенте стековой машины никакой нет. А просто трансляция 1C -> 1C один в один
33. Perfolenta 206 10.06.21 12:26 Сейчас в теме
(26) как там внутри эти клиенты организованы я не знаю, поэтому утверждать ничего не могу... но логично предположить, что если на клиенте появилась асинхронность в языке, а на сервере нет, то там работают два разных интерпретатора...
но так как в JS такая асинхронность есть, я и предположил, что они просто слегка модифицировали транслятор с языка 1С в JS... может быть в тонком клиенте внутри тоже код JS работает, но я этого не знаю, просто предположил...
35. Darklight 33 10.06.21 14:56 Сейчас в теме
(33)
может быть в тонком клиенте внутри тоже код JS работает, но я этого не знаю, просто предположил

Наврядли - ведь код JavaScript нужно на чём-то выполнять. Ради этого жуткого "бутерброда" внедрять в Тонкий клиент JS-машину.... он тонким то после этого останется?
40. Perfolenta 206 11.06.21 09:40 Сейчас в теме
(35) JS машина это очень небольшая библиотечка, а если у Вас уже есть трансляция кода 1С в JS для веб-клиента, то технических проблем я не вижу... наоборот, три абсолютно разных программы-клиента это гораздо более сложный "бутерброд", чем две...
честно говоря, я так и не понял, работают ли асинхронные функции в обычных формах... если нет, то это скорее подтверждает мою гипотезу, а если работает, то опровергает...
42. starik-2005 3088 29.07.21 14:13 Сейчас в теме
(35) JS-машина выполняет "JS-ассемблер" = webassembly. Но это начало развиваться в 15-м, а 1С уже умела что-то творить и в веб-браузере. А веб-браузер не скрывает все то, что в нем выполняется, поэтому посмотреть, что и как работает, труда не должно составить.
WebAssembly (сокращённо wasm) — язык программирования низкого уровня для стековой виртуальной машины, спроектированный как портативная цель компиляции для высокоуровневых языков, таких как Си, C++, C#, Rust, Go. Стековая виртуальная машина, исполняющая инструкции бинарного формата wasm, может быть запущена как в среде браузера, так и в серверной среде. Код на wasm — переносимое абстрактное синтаксическое дерево, что обеспечивает как более быстрый анализ, так и более эффективное выполнение в сравнении с JavaScript.

Проект стартовал 17 июня 2015 года[4], 15 марта 2016 года была продемонстрирована работа игры Angry Bots из набора примеров для Unity в браузере Chromium[5]. Изначально проект основывался на asm.js[6] и PNaCl[7]. В марте 2017 года сообщество разработчиков достигло соглашения о бинарном формате, API для JavaScript и о эталонном интерпретаторе. В конце мая 2017 года команда проекта Chromium объявила о планах по отказу от PNaCl в пользу WebAssembly[8].

По состоянию на конец 2010-х годов группа, работающая над WebAssembly, включает разработчиков из Mozilla, Google, Microsoft и Apple, которые представляют на рынке четыре наиболее распространённых браузера — Firefox, Chrome, Microsoft Edge и Safari соответственно[7].
43. Darklight 33 29.07.21 16:23 Сейчас в теме
(42)\Причём тут WebAssember? В 1С Предприятие 8.3 он точно не используется. Как не использует и JS-Assembeler (это вообще специфический JavaScript код) - предшественник WebAssember. Кстати и тот и другой выполняются на исполнительной среде JS-Runtime - вот как она устроена - это для меня загадка - хотя... кажется что-то видел на презентациях - вроде бы там компиляция в байткод для стековой машины и даже Runtime-компилиция в машинные коды есть (главное с Java мне не напутать).

Ну а так WebAssembler - очень мощная вещь - меня поразило что на нём творят - особенно когда запускал в браузере DooM3 скомпилированный из С++ в WebAssembler.
У микрософта тоже крутая штука есть - Blazor - платформа для компиляции и исполнения C# кода в клиентском или серверном контексте - тоже построена на WebAssembler. Но пока просто взять и скомпилировать уже готовое C# приложение под браузер там нельзя - молодая ещё штука. Нужно специально разрабатывать.

У WebAssembler есть недостатки:
1. Нужно тащить библиотеку в клиент - а они часто не очень маленькие. Вот платформа Blazor весит несколько десятков мегабайт в архиве (кажется в архиве). И это без учета пакета библиотек самого приложения. Правда браузеры это умеют кешировать - но первый раз тащить надо, а потом до изменения будет в кеше.
2. Запуск приложения после загрузки тоже не быстрый
3. Работает заметно медленнее даже в сравнении с не шустрым JavaScript - особенно проседает на кросс-взаимодействии - когда идёт обращение к обычному JavaScript (а через него организованы все браузерные API)

Но это всё проблемы браузеров и они их скорее всего со временем решат.
Вот тогда 1С может возьмёт WebAssembler на вооружение - тут ещё нужно (4 недостаток) иметь удачный компилятор из языка высокого уровня в WebAssembler - ведь вот С++ (который пока поддерживается лучше всего) вроде как 1С хочет уйти. Но свой язык 1С закомпилить в WebAssembler вряд ли будет сложно.

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


Но пока этого нет.
44. starik-2005 3088 29.07.21 17:43 Сейчас в теме
(43)
Работает заметно медленнее даже в сравнении с не шустрым JavaScript
Ну как бы...
Код на wasm — переносимое абстрактное синтаксическое дерево, что обеспечивает как более быстрый анализ, так и более эффективное выполнение в сравнении с JavaScript.

Фактически, wasm - это стековая машина. Во всех современных браузерах есть его поддержка. Для нее есть байт-код, который выполняется в среде виртуальной JS-машины браузера. Фактически, любой язык при наличии компилятора в wasm можно превратить в этот байт-код. 1С тут не исключение. LLVM умеет это делать, для него фактически нужно правила трансляции написать.
45. Darklight 33 29.07.21 18:31 Сейчас в теме
(44)Я не спец по WebAssembly - написал что читал и что сам запускал - в реальных проектах работает медленнее чем JavaScript. Некоторые синтетические тесты выполняются быстрее. Очень редко - заметно быстрее. На операциях взаимодействия с JavaScript API проседания производительности пока очень большие.

Программный код на ЯП можно перевести в WASM - был бы компилятор с этим пока трудности - да для некоторых языком разрабатываются (лень перечислять). Но - во-первых не ве ЯП вообще компилируются в байткод инструкций. Во вторых WASM очень ээээ похож на обычный RISC ASM - т.е. его инструкции достаточно примитивны и ориентированы на простую "алгебру" вычислений. Здесь нет хитрых операций. В этом он очень похож на опКоды 1С. Но это проблема для многих языков - где есь специфические операции - создавать компидятор для них не так то просто. Напрмимер WebAssemvly вроде бы до сих пор нативно не поддерживает никакого менеджера памяти - управление памятью строго явное. Да, тот же Blazor реализовал на нём уже свой менеджер - но это усложняет и утяжелят библиотеки и скомпилированное приложение. А разные ЯП используют свои собственные менеджеры (разных видов). Проще всего Rust - у него большая часть управления памятью происходит статически при компиляции, но подсчёт ссылок в рантайме тоже есть.

LLVM пока с трудом подходит для WebAssembly - просто LLVM - это регистровая машина (и IR-регистровый промежуточный язык) - на стек переводить такой код не очень легко (может быть проще написать компилятор с исходного языка даже). Но да - работы ведутся - ведь вроде бы главный прародитель LLVM сейчас занят в разработке WebAssemly (если не путаю).

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

1С - стековый язык - ему это не проблема. Но ему нужен менеджер памяти (в 1С он на основе подсчёта ссылок).

Есть ещё заморочки с библиотеками - если они скомпилирован под конкретную платформу, то без исходников перевести их на WASM почти нереально. Конечно можно сделать декомпиляцию - но тут своих проблем навалом.

Вот посмотрите на OneScript - условно язык тот же (1С)- но библиотеки под другую платформу приходится писать заново! И это очень тормозит его применение
19. Yashazz 4791 09.06.21 18:10 Сейчас в теме
Скорее всего дело было так: собрались авторы какой-то типовой конфигурации всем коллективом, озверев от необходимости писать кучу вызовов и лишнего кода, пришли к авторам платформы, и эдак проникновенно, вежливо, по-братски попросили хоть что-то с этим сделать. Поскольку тем посылать этих было некомильфо, обещали "что-то придумать", ну и прикрутили кривую приблуду, которая кроме как для файловых операций всерьёз нигде не имеется, не работает и хз как внутри реализована.
21. Alxby 1113 09.06.21 20:21 Сейчас в теме
(19)Почаще бы так собирались. Я бы тоже поучаствовал)
41. mixsture 13.06.21 16:41 Сейчас в теме
По-моему, довольно ожидаемые результаты. Собственно, развитие асинхронности в js шло примерно также. Сначала все подофигели от сложности callback-лапше-кода (и даже придумали термин callback hell). Поэтому дальше родился promise-подход, а дальше async/await. Async/await позволяет писать и видеть перед собой программу будто она синхронная, но куски ее в реальности работают асинхронно. Насколько я знаю, async/await - это как синтаксический сахар, он будто бы дописывает громоздкие конструкции callback за вас. Поэтому ничего нового от него ожидать и не стоит (реальной многопоточности). Это просто удобное и наглядное представление кода.
Насколько я помню, в js он работает также - если вы напишите 2 своих функции с бесконечными циклами внутри, то запустить их параллельно с async/await не выйдет. Это возможно только для специально поддерживаемых функций (которые чаще всего вокруг ввода-вывода).
46. superspy2008 01.12.21 19:50 Сейчас в теме
(41) И довольно ожидаемый очередной комментарий про многопоточность в теме асинхронности. Асинхронность не имеет ничего общего с многопоточностью!! Асинхронность позволит выполнить сотню задач на одном ядре (физически в одном потоке) без ожиданий. Что в C# люди седьмой год от наличия ключевого слова Async ожидают волшебного создания потоков, что в 1С родится и помрет не одно поколение погромистов, уверенных в том же самом.
47. mixsture 04.12.21 17:38 Сейчас в теме
(46) а вы точно комментарий читали? так-то в нем примерно тоже самое написано
48. user595194_bendery_sh 19.02.23 12:17 Сейчас в теме
подскажите, как в синхронной процедуре дождаться результата асинх функции и проверить этот результат, продолжив синхрон по результату асинхрона.
49. Alxby 1113 19.02.23 13:08 Сейчас в теме
(48)Либо я не понял вопроса, либо ответ на него простой - использовать асинхронные функции с конструкцией Ждать, т.е. так, как и предполагается обычное использование асинхронной функции, описанное в документации.
50. user595194_bendery_sh 19.02.23 16:49 Сейчас в теме
(49) все просто

перем а;

процедура Нужная()
а=0;
тест();
// когда и как проверять "а"?
если а=1 тогда б=1
иначе б=0
конецесли;

конецпроцедуры

асинх процедура тест()
слип(рандом); // рандомная задержка
а=1;
конецпроцедуры
51. Alxby 1113 19.02.23 17:31 Сейчас в теме
(50)
Ждать тест();
не подходит?

Не совсем понятна исходная задача.
52. user595194_bendery_sh 19.02.23 21:41 Сейчас в теме
(51) Ждать тест();
это вне языка
53. Alxby 1113 20.02.23 20:39 Сейчас в теме
(52)
Синтаксис:
Ждать <Выражение>;

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


Вполне элемент языка
54. user595194_bendery_sh 20.02.23 23:48 Сейчас в теме
(53) Вот же написано: только в процедурах и функциях, отмеченных как Асинх.

процедура Нужная() - не является Асинх
55. Alxby 1113 21.02.23 08:08 Сейчас в теме
(54)Вы правы, не обратил внимания. А почему нельзя сделать ее Асинх?
Оставьте свое сообщение