I>>>Покажи весь код, для полноты картины. Если UI loop и короутина работают асинхронно, покажи именно эту асинхронщину. Ну и до кучи покажи как руками написать метод навроде getline.
_>>Асинхронность то кодируется совсем не с помощью coroutine, а например (как в моём коде) через std::async. A coroutine нужна что бы вернуть управление после выполнения асинхронной части в код расположенный после кода запуска асинхронной задачи.
I>Правильно, об чем и речь. Потому никаких фокусов нет и быть не может, о чем я и говорю. Короутина нужна для того, что бы сделать энергичный код ленивым, как результат, легко делается кооперативная многозадачность. В винде есть файберы, как раз это же и делают. В бусте сэмулировали эти файберы. В дотнет есть проблема — файберы не поддерживаются рантаймом, и по моему хорошо что так сделано
Ты так говоришь, будет файберы это какие процессорные инструкции. Это те же самые стэковые корутины, просто под виндой их так назвали. А в бусте назвали корутинами.
I>При этом повторяю — нет в короутинах асинхронщины, асинхронщину берет на себя шедулер, который надо еще правильно приготовить, скормить ему набор короутин между которыми он и будет переключаться.
Ну да. В asio этим занимается io_service, который ждёт на каком-нибудь WaitForMultipleObjects, а потом дёргает сработавшие хэндлы.
Здравствуйте, Ikemefula, Вы писали:
M>>Слушай, у меня тут подозрения на счёт await возникло:
M>>
M>>private async void handler(object sender, TaskArgs args)
M>>{
M>> string result = await new Task(() => Download(args.Url), args.Cancellation);
M>> textBox.Text += result;
M>> textBox.Color = Red; // а когда сюда придет управление ??
M>>}
M>>
I>После await, что очевидно. Хандлер развернется в класс, вызывающий метод просто инстанцирует класс и сразу получит управление. А дальше за выполнением кода собственно хандлера будет следить шедулер. Код между await заменится на промисы и замыкания. I>async/await это не короутина, это сахар для вызова шедулера и заворачивания кода в промисы и замыкания, примерно так, короутина всего лишь будет использоваться этим сахаром.
Понятно, что после await. Но до или после завершения скачивания файла? Если до, что за результат будет записан в textBox.Text? Если после, то получается, что handler() будет блокироваться?
Здравствуйте, Ikemefula, Вы писали:
I>>>А где же асинхронщина ? Предположим, это единственный код в приложении, а чтение из стрима занимает 5 минут. Итого — асинхронщина, в твоем понимании, это зависание UI на 5 минут.
M>>Так а после await когда придёт управление? Это же полный аналог твоего кода: M>>
M>>private async void handler(object sender, TaskArgs args)
M>>{
M>> string result = await new Task(() => Download(args.Url), args.Cancellation);
M>> textBox.Text += result; // когда сюда придет управление
M>>}
M>>
I>Нет, это не аналог. Этот хандлер вернет управление сразу, без блокирования, то есть, отпустит UI Loop. А вот внутренности хандлера будут работать иначе — сколько раз эти внутренности пнет шедулер — зависит от кода хандлера.
Стоп. Ты меня не путай.
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work.
Управление к "textBox.Text += result" придёт только после завершения скачки файла. А до этого управление вернётся в код, который вызвал handler() (у тебя видимо это UI Loop). То есть handler() и есть корутина. Поэтому ему и нужно слово async в объявлении. И это есть полная аналогия моего кода. Только у меня вместо UI Loop выступает io_service::run() который выполняет ещё сотню таких же корутин. То есть выполнение корутины будет заблокировано, но выполнение потока, в котором она вызвалась — нет.
Здравствуйте, Ikemefula, Вы писали:
I>Цель этой максимальной быстрости ? Если быстро парсить регэкспы в компайлтайм, то не ясно, как часто это становится узким местом, ибо регэкспы в рантайме это совсем другая вещь. Да и ДСЛ для этого корявый.
Ну вот например я недавно некоторые тесты для разных языков писал и они использовали начальные данные в виде больших (многомегабайтных) текстовых файлов. Так вот я там ради развлечения замерил и время считывания (с парсингом в массивы чисел) этих данных, хотя к делу это не относилось. И вариант на C++ выделялся среди других просто дико — более чем на порядок! Это как раз было результатом использования Boost.Spirit для считывания этих данных. Хотя взял я его не из-за этой скорости, а просто потому что на нём было быстрее всего записать считывание. Т.е. и быстро записывается код и огромная скорость его работы потом.
I>Ты лучше помоги EP, а то он не может асинхрощину найти в синхронном коде. Если нужно решать конкретные задачи — их легко порешать через async/await, безо всяких либов. I>Собтсвенно это короутины, к которым прикручен шедулер. В бусте точно так же и сделано и это одна из причин по которой EP не может объяснить, как короутина вызовт UI Loop — нужно руками добиться этого, например вынести UI loop в такую же короутину. Только здесь получается не асинхронщина, а кооперативная многозадачность, что собтсвенно и делает короутина. Больше ничего она не делает. Вообще. Никогда. Нигде.
Ну да. Просто чистую асинхронщину же и нечего обсуждать. Там всё достаточно тривиально. Оно даже уже в сам стандарт C++11 входит.
I>см выше про кооперативную многозадачность. Если интересно, есть статья про короутины в питоне, там пример такой же мульки. Короутины в C# кастрированые, но они есть — yield. Можно добиься аналогичного, но более многословного варианта по сравнению с питоном.
Ну да. А boost.coroutine ещё покруче питоновских. ))) Но основной принципе безусловно тот же самый.
I>Теперь никаких претензий нет или ты все еще хочешь что бы я добавил еще одну строчку в свой пример навроде result = await result.Content.GetBytes() ?
Ой, да мы вроде уже давно выяснили что мой вариант реализации await/async для C++ выглядит немного страшнее чем C# вариант, но при этом даёт чуть-чуть больше гибкости. Утомили уже эти примеры. Кстати, изначально это был пример от gandjustas. Только вот он написал "Давай, детка, сделай это на C++.", а потом резко пропал куда-то...
Здравствуйте, alex_public, Вы писали:
I>>Цель этой максимальной быстрости ? Если быстро парсить регэкспы в компайлтайм, то не ясно, как часто это становится узким местом, ибо регэкспы в рантайме это совсем другая вещь. Да и ДСЛ для этого корявый.
_> Так вот я там ради развлечения замерил
I>>Теперь никаких претензий нет или ты все еще хочешь что бы я добавил еще одну строчку в свой пример навроде result = await result.Content.GetBytes() ?
_>Ой, да мы вроде уже давно выяснили что мой вариант реализации await/async для C++ выглядит немного страшнее чем C# вариант, но при этом даёт чуть-чуть больше гибкости. Утомили уже эти примеры. Кстати, изначально это был пример от gandjustas. Только вот он написал "Давай, детка, сделай это на C++.", а потом резко пропал куда-то...
Я скажу страшное — буст очень часто не используют по политическим причинам.
Здравствуйте, Mazay, Вы писали:
I>>После await, что очевидно. Хандлер развернется в класс, вызывающий метод просто инстанцирует класс и сразу получит управление. А дальше за выполнением кода собственно хандлера будет следить шедулер. Код между await заменится на промисы и замыкания. I>>async/await это не короутина, это сахар для вызова шедулера и заворачивания кода в промисы и замыкания, примерно так, короутина всего лишь будет использоваться этим сахаром.
M>Понятно, что после await. Но до или после завершения скачивания файла? Если до, что за результат будет записан в textBox.Text? Если после, то получается, что handler() будет блокироваться?
Унутре — будет конечно, await именно это и делает. Вызывающий код — нет. EP показал _другой_ пример, где блокируется сам вызывающий код.
Здравствуйте, Ikemefula, Вы писали:
I>Правильно, об чем и речь. Потому никаких фокусов нет и быть не может, о чем я и говорю. Короутина нужна для того, что бы сделать энергичный код ленивым, как результат, легко делается кооперативная многозадачность. В винде есть файберы, как раз это же и делают. В бусте сэмулировали эти файберы. В дотнет есть проблема — файберы не поддерживаются рантаймом, и по моему хорошо что так сделано I>При этом повторяю — нет в короутинах асинхронщины, асинхронщину берет на себя шедулер, который надо еще правильно приготовить, скормить ему набор короутин между которыми он и будет переключаться.
Конечно. Но с помощью таких инструментов как boost.coroutine и std::async подобный шедулер кодируется буквально в 5 строк кода. И это не преувеличение для красного словца, а именно факт показанный мною в этой темке. Правда эти строки несколько страшненькие, так что пришлось их срочно спрятать за макросами. ))) Но думаю сам факт реализации await/async модели в 5 строк на C++ весьма показателен. Особенно с учётом того, что это писалось в ответ на предположения о невозможности такого в C++ в принципе. )))
Здравствуйте, Mazay, Вы писали:
I>>Правильно, об чем и речь. Потому никаких фокусов нет и быть не может, о чем я и говорю. Короутина нужна для того, что бы сделать энергичный код ленивым, как результат, легко делается кооперативная многозадачность. В винде есть файберы, как раз это же и делают. В бусте сэмулировали эти файберы. В дотнет есть проблема — файберы не поддерживаются рантаймом, и по моему хорошо что так сделано
M>Ты так говоришь, будет файберы это какие процессорные инструкции. Это те же самые стэковые корутины, просто под виндой их так назвали. А в бусте назвали корутинами.
Я в курсе, не боись.
I>>При этом повторяю — нет в короутинах асинхронщины, асинхронщину берет на себя шедулер, который надо еще правильно приготовить, скормить ему набор короутин между которыми он и будет переключаться.
M>Ну да. В asio этим занимается io_service, который ждёт на каком-нибудь WaitForMultipleObjects, а потом дёргает сработавшие хэндлы.
в первом страшненьком куске кода ставится "маркер" (точнее даже два, т.к. там две асинхронности) на одну часть кода программы. А потом идёт отдельный кусок кода из двух строк для вставки в обработчик UI потока — это второй "маркер" ставится.
Здравствуйте, alex_public, Вы писали:
_>Конечно. Но с помощью таких инструментов как boost.coroutine и std::async подобный шедулер кодируется буквально в 5 строк кода. И это не преувеличение для красного словца, а именно факт показанный мною в этой темке.
Такой шедулер писать нужно долго и упорно, взять хотя бы реализацию Round Robin.
>Правда эти строки несколько страшненькие, так что пришлось их срочно спрятать за макросами. ))) Но думаю сам факт реализации await/async модели в 5 строк на C++ весьма показателен. Особенно с учётом того, что это писалось в ответ на предположения о невозможности такого в C++ в принципе. )))
Здравствуйте, Mazay, Вы писали:
EP>>getline тут самый стандартный, который std::getline. M>Ну ты не перебарщивай. К этому getline нужна таки обёртка, которая будет откидывать управление из корутины и получать его назад, по типу той что я писал выше.
getline там стандартный, не перегруженный
А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>getline там стандартный, не перегруженный EP>А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream
Ну значит UI Loop из моего примера вызовется чудом, например сканированием адресного пространства на предмет наличия ::GetMessage и ::TranslateMessage или, как вариант, короутина догадается WinMain вызвать.
Здравствуйте, Ikemefula, Вы писали:
EP>>>getline тут самый стандартный, который std::getline. M>>Ну ты не перебарщивай. К этому getline нужна таки обёртка, которая будет откидывать управление из корутины и получать его назад, по типу той что я писал выше. I>Качественно ты его слил
getline там стандартный
[...] I>Я тебя не путаю, Выше по контексту пример синхронного getline и тд и тд и тд.
Тот код асинхронный
[...] I> Ты лучше помоги EP, а то он не может асинхрощину найти в синхронном коде
[...] I> Покажи этот код, а то вот EP не может
Балабольство чистой воды
Тот код с getline я скопировал из примеров к Boost.Coroutine, о чём сразу и сказал
Например, в examples к Boost.Coroutine есть пример простого сервера, который асинхронно считывает сообщения из tcp порта и выводит их на экран — причём всё это происходит в одном потоке. Цикл считывания выглядит точно также как и обыкновенный синхронный код:
Вникай, там асинхронные соединения, и getline стадартный
Здравствуйте, Ikemefula, Вы писали:
I>Такой шедулер писать нужно долго и упорно, взять хотя бы реализацию Round Robin.
Ну так в большинстве случаем мы тут просто используем планировщик из ОС. Хотя если использовать std::async из последнего msvc, то там оно вроде как использует небольшой пул потоков и само перекидывает задачки между ними.
I>ты спрятал не шедулер, а всего лишь ожидание.
Так о том и речь, что это единственно что пришлось дописать, а всё остальное уже в языке/библиотеках реализовано.
В функцию foo, я добавил вывод уникальной части — в остальном всё идентично коду показанному выше.
Сопроцедуры работают асинхронно, а getline стандартный, ага.
Чтобы было понятней, stackfull coroutine это двусторонний портал — в него можно нырнуть с двух сторон.
Здесь один конец находится в "event-loop", а другой в асинхронном вызове.
Когда асинхронному коду нужны данные — он ныряет в свой портал.
Когда "event-loop" видит что пришли данные — он просто ныряет в нужный портал в зависимости от того, кому эти данные адресуются.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>В функцию foo, я добавил вывод уникальной части — в остальном всё идентично коду показанному выше. EP>Сопроцедуры работают асинхронно, а getline стандартный, ага.
Ты бы еще привел пример операциооной системы. Все что от тебя требовалось — минимально возможный код который показывает как работает собтсвенно переключение задач для асинхронной задачи.
Странно, но ты снова привел __синхронный__ код Если короутина прыгает между стеками, еще не значит, что код автоматически становится асинхронным. Ну и так же ты показал, что в предыдущем примере у тебя, мягко говоря, отсутствовало 99% решения
Здравствуйте, Ikemefula, Вы писали:
EP>>В функцию foo, я добавил вывод уникальной части — в остальном всё идентично коду показанному выше. EP>>Сопроцедуры работают асинхронно, а getline стандартный, ага. I>Ты бы еще привел пример операциооной системы. Все что от тебя требовалось — минимально возможный код который показывает как работает собтсвенно переключение задач для асинхронной задачи.
Минимально достаточного того, что я писал — почему-то до других дошло
I>Странно, но ты снова привел __синхронный__ код Если короутина прыгает между стеками, еще не значит, что код автоматически становится асинхронным.
Asynchronous I/O, in computer science, is a form of input/output processing that permits other processing to continue before the transmission has finished.
Вызываются "handler"'ы (в твоих терминах).
В каждом "handler"'е код выполняется до каждого yield'а и сразу возвращается сюда — так же как и в C# с async/await код выполняется до первого await'а. Это в твоих понятиях являются асинхронными вызовами или нет?
Когда "event loop" ныряет в сопроцедуру — это аналог тому, когда await дожидается своего таска.
Все остальные yield'ы в "handler"'ах — аналогичны последующим await'ам и т.п.
I>Ну и так же ты показал, что в предыдущем примере у тебя, мягко говоря, отсутствовало 99% решения
Опустим этот "толстый, толстый слой шоколада" и вернёмся к исходному вопросу
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, Mazay, Вы писали:
EP>>>getline тут самый стандартный, который std::getline. M>>Ну ты не перебарщивай. К этому getline нужна таки обёртка, которая будет откидывать управление из корутины и получать его назад, по типу той что я писал выше.
EP>getline там стандартный, не перегруженный EP>А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream
Аааа. Тады ой. Тады всё правильно — полный аналог await.
Здравствуйте, Mazay, Вы писали:
EP>>А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream M>Аааа. Тады ой. Тады всё правильно — полный аналог await.
Ну да, только мощнее.
Если всё же заменить на std::istream:
То этот код будет работать с любыми потоками — что с синхронными, что с асинхронными, потому что код одинаковый для обоих случаев, так как можно yield спрятать внутри сокета.
На await-те так не получится — в асинхронной версии будет await(+async в объявлении) + по всему call stack'у выше, вплоть до вызова handler'а, точно также будут добавляться await+await.