Re[30]: Что посоветуете как аналог С++
От: Mazay Россия  
Дата: 25.06.13 18:10
Оценка: +1
Здравствуйте, Ikemefula, Вы писали:


I>>>Покажи весь код, для полноты картины. Если UI loop и короутина работают асинхронно, покажи именно эту асинхронщину. Ну и до кучи покажи как руками написать метод навроде getline.


_>>Асинхронность то кодируется совсем не с помощью coroutine, а например (как в моём коде) через std::async. A coroutine нужна что бы вернуть управление после выполнения асинхронной части в код расположенный после кода запуска асинхронной задачи.


I>Правильно, об чем и речь. Потому никаких фокусов нет и быть не может, о чем я и говорю. Короутина нужна для того, что бы сделать энергичный код ленивым, как результат, легко делается кооперативная многозадачность. В винде есть файберы, как раз это же и делают. В бусте сэмулировали эти файберы. В дотнет есть проблема — файберы не поддерживаются рантаймом, и по моему хорошо что так сделано


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

I>При этом повторяю — нет в короутинах асинхронщины, асинхронщину берет на себя шедулер, который надо еще правильно приготовить, скормить ему набор короутин между которыми он и будет переключаться.


Ну да. В asio этим занимается io_service, который ждёт на каком-нибудь WaitForMultipleObjects, а потом дёргает сработавшие хэндлы.
Главное гармония ...
Re[30]: Что посоветуете как аналог С++
От: Mazay Россия  
Дата: 25.06.13 18:15
Оценка:
Здравствуйте, 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() будет блокироваться?
Главное гармония ...
Re[28]: Что посоветуете как аналог С++
От: Mazay Россия  
Дата: 25.06.13 18:26
Оценка:
Здравствуйте, 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() который выполняет ещё сотню таких же корутин. То есть выполнение корутины будет заблокировано, но выполнение потока, в котором она вызвалась — нет.
Главное гармония ...
Re[43]: Что посоветуете как аналог С++
От: alex_public  
Дата: 25.06.13 18:37
Оценка: +1 :)
Здравствуйте, 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++.", а потом резко пропал куда-то...
Re[44]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.06.13 18:41
Оценка: :)
Здравствуйте, alex_public, Вы писали:

I>>Цель этой максимальной быстрости ? Если быстро парсить регэкспы в компайлтайм, то не ясно, как часто это становится узким местом, ибо регэкспы в рантайме это совсем другая вещь. Да и ДСЛ для этого корявый.


_> Так вот я там ради развлечения замерил




I>>Теперь никаких претензий нет или ты все еще хочешь что бы я добавил еще одну строчку в свой пример навроде result = await result.Content.GetBytes() ?


_>Ой, да мы вроде уже давно выяснили что мой вариант реализации await/async для C++ выглядит немного страшнее чем C# вариант, но при этом даёт чуть-чуть больше гибкости. Утомили уже эти примеры. Кстати, изначально это был пример от gandjustas. Только вот он написал "Давай, детка, сделай это на C++.", а потом резко пропал куда-то...


Я скажу страшное — буст очень часто не используют по политическим причинам.
Re[29]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.06.13 18:45
Оценка:
Здравствуйте, Mazay, Вы писали:

M>Стоп. Ты меня не путай.


Я тебя не путаю, Выше по контексту пример синхронного getline и тд и тд и тд.
Re[31]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.06.13 18:47
Оценка:
Здравствуйте, Mazay, Вы писали:

I>>После await, что очевидно. Хандлер развернется в класс, вызывающий метод просто инстанцирует класс и сразу получит управление. А дальше за выполнением кода собственно хандлера будет следить шедулер. Код между await заменится на промисы и замыкания.

I>>async/await это не короутина, это сахар для вызова шедулера и заворачивания кода в промисы и замыкания, примерно так, короутина всего лишь будет использоваться этим сахаром.

M>Понятно, что после await. Но до или после завершения скачивания файла? Если до, что за результат будет записан в textBox.Text? Если после, то получается, что handler() будет блокироваться?


Унутре — будет конечно, await именно это и делает. Вызывающий код — нет. EP показал _другой_ пример, где блокируется сам вызывающий код.
Re[30]: Что посоветуете как аналог С++
От: alex_public  
Дата: 25.06.13 18:48
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Правильно, об чем и речь. Потому никаких фокусов нет и быть не может, о чем я и говорю. Короутина нужна для того, что бы сделать энергичный код ленивым, как результат, легко делается кооперативная многозадачность. В винде есть файберы, как раз это же и делают. В бусте сэмулировали эти файберы. В дотнет есть проблема — файберы не поддерживаются рантаймом, и по моему хорошо что так сделано

I>При этом повторяю — нет в короутинах асинхронщины, асинхронщину берет на себя шедулер, который надо еще правильно приготовить, скормить ему набор короутин между которыми он и будет переключаться.

Конечно. Но с помощью таких инструментов как boost.coroutine и std::async подобный шедулер кодируется буквально в 5 строк кода. И это не преувеличение для красного словца, а именно факт показанный мною в этой темке. Правда эти строки несколько страшненькие, так что пришлось их срочно спрятать за макросами. ))) Но думаю сам факт реализации await/async модели в 5 строк на C++ весьма показателен. Особенно с учётом того, что это писалось в ответ на предположения о невозможности такого в C++ в принципе. )))
Re[31]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.06.13 18:48
Оценка:
Здравствуйте, Mazay, Вы писали:

I>>Правильно, об чем и речь. Потому никаких фокусов нет и быть не может, о чем я и говорю. Короутина нужна для того, что бы сделать энергичный код ленивым, как результат, легко делается кооперативная многозадачность. В винде есть файберы, как раз это же и делают. В бусте сэмулировали эти файберы. В дотнет есть проблема — файберы не поддерживаются рантаймом, и по моему хорошо что так сделано


M>Ты так говоришь, будет файберы это какие процессорные инструкции. Это те же самые стэковые корутины, просто под виндой их так назвали. А в бусте назвали корутинами.


Я в курсе, не боись.

I>>При этом повторяю — нет в короутинах асинхронщины, асинхронщину берет на себя шедулер, который надо еще правильно приготовить, скормить ему набор короутин между которыми он и будет переключаться.


M>Ну да. В asio этим занимается io_service, который ждёт на каком-нибудь WaitForMultipleObjects, а потом дёргает сработавшие хэндлы.


!!!
Re[30]: Что посоветуете как аналог С++
От: alex_public  
Дата: 25.06.13 19:01
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Покажи этот код, а то вот EP не может


Так в изначальном сообщение, которое ещё без макросов, было всё целиком. Вот тут http://www.rsdn.ru/forum/philosophy/5209186
Автор: alex_public
Дата: 24.06.13
в первом страшненьком куске кода ставится "маркер" (точнее даже два, т.к. там две асинхронности) на одну часть кода программы. А потом идёт отдельный кусок кода из двух строк для вставки в обработчик UI потока — это второй "маркер" ставится.
Re[31]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.06.13 19:09
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Конечно. Но с помощью таких инструментов как boost.coroutine и std::async подобный шедулер кодируется буквально в 5 строк кода. И это не преувеличение для красного словца, а именно факт показанный мною в этой темке.


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

>Правда эти строки несколько страшненькие, так что пришлось их срочно спрятать за макросами. ))) Но думаю сам факт реализации await/async модели в 5 строк на C++ весьма показателен. Особенно с учётом того, что это писалось в ответ на предположения о невозможности такого в C++ в принципе. )))


ты спрятал не шедулер, а всего лишь ожидание.
Re[30]: Что посоветуете как аналог С++
От: Evgeny.Panasyuk Россия  
Дата: 25.06.13 19:20
Оценка:
Здравствуйте, Mazay, Вы писали:

EP>>getline тут самый стандартный, который std::getline.

M>Ну ты не перебарщивай. К этому getline нужна таки обёртка, которая будет откидывать управление из корутины и получать его назад, по типу той что я писал выше.

getline там стандартный, не перегруженный
А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream
Re[31]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.06.13 19:34
Оценка: :))
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>getline там стандартный, не перегруженный

EP>А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream

Ну значит UI Loop из моего примера вызовется чудом, например сканированием адресного пространства на предмет наличия ::GetMessage и ::TranslateMessage или, как вариант, короутина догадается WinMain вызвать.
Re[31]: Что посоветуете как аналог С++
От: Evgeny.Panasyuk Россия  
Дата: 25.06.13 19:42
Оценка:
Здравствуйте, Ikemefula, Вы писали:

EP>>>getline тут самый стандартный, который std::getline.

M>>Ну ты не перебарщивай. К этому getline нужна таки обёртка, которая будет откидывать управление из корутины и получать его назад, по типу той что я писал выше.
I>Качественно ты его слил

getline там стандартный

[...]
I>Я тебя не путаю, Выше по контексту пример синхронного getline и тд и тд и тд.

Тот код асинхронный

[...]
I> Ты лучше помоги EP, а то он не может асинхрощину найти в синхронном коде
[...]
I> Покажи этот код, а то вот EP не может

Балабольство чистой воды

Тот код с getline я скопировал из примеров к Boost.Coroutine, о чём сразу и сказал
Автор: Evgeny.Panasyuk
Дата: 21.06.13
:

Например, в examples к Boost.Coroutine есть пример простого сервера, который асинхронно считывает сообщения из tcp порта и выводит их на экран — причём всё это происходит в одном потоке. Цикл считывания выглядит точно также как и обыкновенный синхронный код:

Вникай, там асинхронные соединения, и getline стадартный
Re[32]: Что посоветуете как аналог С++
От: alex_public  
Дата: 25.06.13 19:46
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Такой шедулер писать нужно долго и упорно, взять хотя бы реализацию Round Robin.


Ну так в большинстве случаем мы тут просто используем планировщик из ОС. Хотя если использовать std::async из последнего msvc, то там оно вроде как использует небольшой пул потоков и само перекидывает задачки между ними.

I>ты спрятал не шедулер, а всего лишь ожидание.


Так о том и речь, что это единственно что пришлось дописать, а всё остальное уже в языке/библиотеках реализовано.
Re[30]: Что посоветуете как аналог С++
От: Evgeny.Panasyuk Россия  
Дата: 25.06.13 21:45
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Я этот код не понимаю и там так же не очевидно, как именно вернется управление в UI Loop


Полностью локализованный код, со своим scheduler'ом, блэкджеком и шлюхами:
#include <boost/range/algorithm_ext.hpp>
#include <boost/range/algorithm.hpp>

#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/stream.hpp>

#include <boost/coroutine/all.hpp>

#include <functional>
#include <algorithm>
#include <iostream>
#include <cstddef>
#include <utility>
#include <string>
#include <vector>
#include <deque>

using namespace boost;
using namespace std;
using namespace placeholders;

typedef coroutines::coroutine<void()> Coro;
typedef deque<char> Buffer;

struct DataSource
{
    typedef char        char_type;
    typedef iostreams::source_tag category;

    Coro::caller_type &ca;
    Buffer &buffer;

    std::streamsize read(char* out, streamsize n)
    {
        if(buffer.empty())
        {
            ca();
            if(buffer.empty()) return -1;
        }
        auto actual_n = min(n, streamsize(buffer.size()));
        auto first = buffer.begin();
        auto last = first + actual_n;
        copy(first, last, out);
        buffer.erase(first, last);
        return actual_n;
    }
};
typedef iostreams::stream<DataSource> TcpStream;

void foo(TcpStream &client_stream)
{
    string msg;
    do
    {
        getline(client_stream, msg);
        cout << "stream address: " << &client_stream << "|\t";
        cout << msg << endl;
    } while(msg != "exit");
}

void coroutine_start(Buffer *buffer,Coro::caller_type &ca)
{
    DataSource source{ca, *buffer};
    TcpStream client_stream(source);
    foo(client_stream);
}

int main()
{
    vector<Coro> fibers;
    vector<Buffer> buffers(4);
    for(auto &buffer : buffers)
        fibers.emplace_back(bind(coroutine_start, &buffer, _1));

    struct StreamData
    {
        size_t receiver;
        string msg;
    } const stream_datas[] =
    {
        {0, "Hello"},
        {1, "World"},
        {2, "Stackfull"},
        {3, "Coroutines"},
        {2, "Rulez!"},
        {1, "Hasta la vista"},
        {0, "Baby"}
    };

    for(auto &sd : stream_datas)
    {
        auto &buffer = buffers[sd.receiver];
        push_back(buffer, sd.msg);
        buffer.push_back('\n');
        fibers[sd.receiver]();
    }

    for(auto &buffer : buffers)
        push_back(buffer, "exit\n");
    for(auto &c : fibers)
       c();
}

Вывод:
stream address: 0x7fc742afdc10| Hello
stream address: 0x7fc742aebc10| World
stream address: 0x7fc742ad9c10| Stackfull
stream address: 0x7fc742ac7c10| Coroutines
stream address: 0x7fc742ad9c10| Rulez!
stream address: 0x7fc742aebc10| Hasta la vista
stream address: 0x7fc742afdc10| Baby
stream address: 0x7fc742afdc10| exit
stream address: 0x7fc742aebc10| exit
stream address: 0x7fc742ad9c10| exit
stream address: 0x7fc742ac7c10| exit

В функцию foo, я добавил вывод уникальной части — в остальном всё идентично коду показанному выше.
Сопроцедуры работают асинхронно, а getline стандартный, ага.

Чтобы было понятней, stackfull coroutine это двусторонний портал — в него можно нырнуть с двух сторон.

Здесь один конец находится в "event-loop", а другой в асинхронном вызове.
Когда асинхронному коду нужны данные — он ныряет в свой портал.
Когда "event-loop" видит что пришли данные — он просто ныряет в нужный портал в зависимости от того, кому эти данные адресуются.
Re[31]: Что посоветуете как аналог С++
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.06.13 03:09
Оценка: :))
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>В функцию foo, я добавил вывод уникальной части — в остальном всё идентично коду показанному выше.

EP>Сопроцедуры работают асинхронно, а getline стандартный, ага.

Ты бы еще привел пример операциооной системы. Все что от тебя требовалось — минимально возможный код который показывает как работает собтсвенно переключение задач для асинхронной задачи.

Странно, но ты снова привел __синхронный__ код Если короутина прыгает между стеками, еще не значит, что код автоматически становится асинхронным. Ну и так же ты показал, что в предыдущем примере у тебя, мягко говоря, отсутствовало 99% решения

P.S. если нужны примеры попроще, вот http://www.crystalclearsoftware.com/soc/coroutine/, это гораздо полезнее.
Re[32]: Что посоветуете как аналог С++
От: Evgeny.Panasyuk Россия  
Дата: 26.06.13 04:05
Оценка:
Здравствуйте, Ikemefula, Вы писали:

EP>>В функцию foo, я добавил вывод уникальной части — в остальном всё идентично коду показанному выше.

EP>>Сопроцедуры работают асинхронно, а getline стандартный, ага.
I>Ты бы еще привел пример операциооной системы. Все что от тебя требовалось — минимально возможный код который показывает как работает собтсвенно переключение задач для асинхронной задачи.

Минимально достаточного того, что я писал — почему-то до других дошло

I>Странно, но ты снова привел __синхронный__ код Если короутина прыгает между стеками, еще не значит, что код автоматически становится асинхронным.


http://en.wikipedia.org/wiki/Asynchronous_I/O

Asynchronous I/O, in computer science, is a form of input/output processing that permits other processing to continue before the transmission has finished.



Вот тут:
for(auto &buffer : buffers)
        fibers.emplace_back(bind(coroutine_start, &buffer, _1));

Вызываются "handler"'ы (в твоих терминах).
В каждом "handler"'е код выполняется до каждого yield'а и сразу возвращается сюда — так же как и в C# с async/await код выполняется до первого await'а. Это в твоих понятиях являются асинхронными вызовами или нет?
Когда "event loop" ныряет в сопроцедуру — это аналог тому, когда await дожидается своего таска.
Все остальные yield'ы в "handler"'ах — аналогичны последующим await'ам и т.п.

I>Ну и так же ты показал, что в предыдущем примере у тебя, мягко говоря, отсутствовало 99% решения


Опустим этот "толстый, толстый слой шоколада" и вернёмся к исходному вопросу
Автор: Evgeny.Panasyuk
Дата: 25.06.13
.
Аналогичный код можно написать на await'ах — но там неизбежно "асинхронные кишки будут торчать в клиентском коде". Ты теперь понял почему?
Re[31]: Что посоветуете как аналог С++
От: Mazay Россия  
Дата: 26.06.13 04:21
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Здравствуйте, Mazay, Вы писали:


EP>>>getline тут самый стандартный, который std::getline.

M>>Ну ты не перебарщивай. К этому getline нужна таки обёртка, которая будет откидывать управление из корутины и получать его назад, по типу той что я писал выше.

EP>getline там стандартный, не перегруженный

EP>А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream

Аааа. Тады ой. Тады всё правильно — полный аналог await.
Главное гармония ...
Re[32]: Что посоветуете как аналог С++
От: Evgeny.Panasyuk Россия  
Дата: 26.06.13 04:42
Оценка:
Здравствуйте, Mazay, Вы писали:

EP>>А stream да — специальный, я этого и не скрывал — в том коде даже тип для стрима специальный, хотя можно было показать только std::istream

M>Аааа. Тады ой. Тады всё правильно — полный аналог await.

Ну да, только мощнее.
Если всё же заменить на std::istream:
void foo(std::istream &client_stream)
{
    string msg;
    do
    {
        getline(client_stream, msg);
        cout << msg << endl; 
    } while(msg != "exit");
}

То этот код будет работать с любыми потоками — что с синхронными, что с асинхронными, потому что код одинаковый для обоих случаев, так как можно yield спрятать внутри сокета.

На await-те так не получится — в асинхронной версии будет await(+async в объявлении) + по всему call stack'у выше, вплоть до вызова handler'а, точно также будут добавляться await+await.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.