Здравствуйте, artelk, Вы писали:
A>1. Покажи, как это будет выглядеть, если foo возвращает результат? Причем, чтобы было, что "код который вызывает foo может ничего не знать об асинхронности".
Result foo(std::istream &client_stream)
{
string msg;
do
{
getline(client_stream, msg);
cout << msg << endl;
} while(msg != "exit");
// ...return result;
}
Result bar(std::istream &client1, std::istream &client2)
{
auto result = foo(client1) + foo(client2);
return result;
}
A>2. Покажи, как это будет выглядеть, если foo принимает не istream&, а, например, адрес или путь к файлу.
Result foo(Address &address)
{
TcpStream client_stream(address); // or factory, or type template parameter
string msg;
// ... same as above
}
EP>>>>На await-те так не получится — в асинхронной версии будет await(+async в объявлении) + по всему call stack'у выше, вплоть до вызова handler'а, точно также будут добавляться await+await. A>Async не является частью сигнатуры — можешь вызвать как обычную функцию и что-то делать с возвращаемым Task-ом.
Я знаю А ещё можно "просто вызвать" (ничего не делая с Task'ом), если результат не важен.
A>Но таки да, придется возвращать Task<TResult>, вместо TResult, чтобы можно было делать "TResult r = await foo();". А что, на C++ можно вернуть TResult и сделать асинхронщину?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Здравствуйте, artelk, Вы писали:
A>>1. Покажи, как это будет выглядеть, если foo возвращает результат? Причем, чтобы было, что "код который вызывает foo может ничего не знать об асинхронности".
EP>
Т.е. вызывающий поток блокируется до тех пор, пока Result не будет вычислен?
A>>2. Покажи, как это будет выглядеть, если foo принимает не istream&, а, например, адрес или путь к файлу.
EP>
EP>Result foo(Address &address)
EP>{
EP> TcpStream client_stream(address); // or factory, or type template parameter
EP> string msg;
EP> // ... same as above
EP>}
EP>
TcpStream — это какой-то специальный stream, который периодически делает yield?
Здравствуйте, artelk, Вы писали:
A>>>1. Покажи, как это будет выглядеть, если foo возвращает результат? Причем, чтобы было, что "код который вызывает foo может ничего не знать об асинхронности". EP>>
A>Т.е. вызывающий поток блокируется до тех пор, пока Result не будет вычислен?
По смыслу, это примерно тоже самое, что и:
asyncTask<Result> bar(istream client1, istream client2)
{
var result = await foo(client1) + await foo(client2);
return result;
}
Вызывающий поток(thread) не блокируется, а возвращается к другим задачам, например по event loop.
A>>>2. Покажи, как это будет выглядеть, если foo принимает не istream&, а, например, адрес или путь к файлу. EP>>
EP>>Result foo(Address &address)
EP>>{
EP>> TcpStream client_stream(address); // or factory, or type template parameter
EP>> string msg;
EP>> // ... same as above
EP>>}
EP>>
A>TcpStream — это какой-то специальный stream, который периодически делает yield?
Да, только не периодически, а по необходимости. Внутри у него что-то типа:
async_read(connection, buffer, /* completion callback: */ [coro]{ coro.resume(); } );
coro.yeild(); // "sleep", will be awakened by completion callback
Причём у него интерфейс как у обычного блокирующего потока, без намёков на асинхронность, поэтому он и совместим с std::istream.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
A>>Но таки да, придется возвращать Task<TResult>, вместо TResult, чтобы можно было делать "TResult r = await foo();". А что, на C++ можно вернуть TResult и сделать асинхронщину?
EP>Да, именно так — с помощью stackful coroutines.
Ну раз так, покажи два способа вызова getline, например один вызвали и ожидаем результата, второй раз вызвали и результата НЕ ожидаем а получаем когда нибудь потом.
Здравствуйте, artelk, Вы писали:
A>Т.е. вызывающий поток блокируется до тех пор, пока Result не будет вычислен?
Именно так и он это называет асинхронщиной, потому что де в этом потоке будет выполняться какая нибудь другая короутина, которая делает хрен знает что.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>По смыслу, это примерно тоже самое, что и: EP>
EP>asyncTask<Result> bar(istream client1, istream client2)
EP>{
EP> var result = await foo(client1) + await foo(client2);
EP> return result;
EP>}
EP>
EP>Вызывающий поток(thread) не блокируется, а возвращается к другим задачам, например по event loop.
Для этого надо псать специальный код. А как сделать версию того кода, что не вызвает await ?
EP>Причём у него интерфейс как у обычного блокирующего потока, без намёков на асинхронность, поэтому он и совместим с std::istream.
То есть, его можно использовать ровно одним способом или синхронно или асинхронно. При этом await позволаяет включать ожидание там где тебе надо.
EP>>>То этот код будет работать с любыми потоками — что с синхронными, что с асинхронными, потому что код одинаковый для обоих случаев, так как можно yield спрятать внутри сокета.
EP>Уверен
. EP>Да, асинхронный код можно легко сделать синхронным, но как тут уже не раз обсуждалось — getline тут стандартный, изначально ничего не знающий об асинхронности — std::istream тоже самый обычный. Код который вызывает void foo также может ничего не знать об асинхронности — он просто передаёт istream&.
Ты лучше сделай наконец тот пример что я тебя просил. Ну или покажи как один раз вызвать getline с ожиданием а другой раз без ожидания.
Здравствуйте, Ikemefula, Вы писали:
A>>Т.е. вызывающий поток блокируется до тех пор, пока Result не будет вычислен? I>Именно так и он это называет асинхронщиной, потому что де в этом потоке будет выполняться какая нибудь другая короутина,
Так ты определись — либо блокируется, либо "в этом потоке"
I>которая делает хрен знает что.
Здравствуйте, Ikemefula, Вы писали:
EP>>По смыслу, это примерно тоже самое, что и: EP>>
EP>>asyncTask<Result> bar(istream client1, istream client2)
EP>>{
EP>> var result = await foo(client1) + await foo(client2);
EP>> return result;
EP>>}
EP>>
EP>>Вызывающий поток(thread) не блокируется, а возвращается к другим задачам, например по event loop. I>Для этого надо псать специальный код.
Этот код пишется один раз, и едет библиотеку, при этом ни каркас приложения, ни event loop — не меняются.
I>То есть, его можно использовать ровно одним способом или синхронно или асинхронно.
О, уже прогресс!
I>При этом await позволаяет включать ожидание там где тебе надо.
Так и тут при необходимости можно явно указать где не нужно ожидание
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>>>Вызывающий поток(thread) не блокируется, а возвращается к другим задачам, например по event loop. I>>Для этого надо псать специальный код.
EP>Этот код пишется один раз, и едет библиотеку, при этом ни каркас приложения, ни event loop — не меняются.
Ну это просто вранье. alex_public показал, как event-loop "не меняется" — путем встраивания RunAll в event loop или прикручивая таймер
I>>При этом await позволаяет включать ожидание там где тебе надо.
EP>Так и тут при необходимости можно явно указать где не нужно ожидание
Продемонстрируй свой getline один раз с ожиданием, другой раз без ожидания. Надеюсь, ты не станешь эмулировать await путем параметризации gitline специальным потоком ?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
A>>>Т.е. вызывающий поток блокируется до тех пор, пока Result не будет вычислен? I>>Именно так и он это называет асинхронщиной, потому что де в этом потоке будет выполняться какая нибудь другая короутина,
EP>Так ты определись — либо блокируется, либо "в этом потоке"
UI поток заблокируется, потому что буст не знает про message pump. В этом потоке будет чтото выполняться, при чем не ясно, как указать что именно должно выполняться.
Все твои примеры "асинхронщины" это просто синхронный код с нелокальными переходами. Все, больше ничего в твоих примерах нет и быть не может. Асинхронщину показал alex_publiс, у тебя же общие слова "все шоколадно, все само и тд"
Представь себе либу, которая ничего про твои короутины не знает. У ней ровно один метод, как водится, блокирующий, это именно то ради чего нужна асинхронщина:
А ведь кторо говорил что никакие уши асинхронщины нигде не торчат Похоже, у вас с vdimas стало модно брать свои слова назад.
собтсвенно если немного уйти от getline, в которым можно спрятать асинхронщину в поток, и взять чтото навроде
string s = ::ReadFileAsUrl("someConfigPath")
То внезапно оказывается так, что асинхронщина пролезет даже в сигнатуру. Ну или как вариант, придется указывать наличие/отсутствие ожидания с помощью глобальных переменных
Остался один открытый вопрос — сделать так, что бы буст, наконец, узнал про message pump.
Здравствуйте, Ikemefula, Вы писали:
EP>>Так ты определись — либо блокируется, либо "в этом потоке"
I>UI поток заблокируется, потому что буст не знает про message pump. В этом потоке будет чтото выполняться, при чем не ясно, как указать что именно должно выполняться.
Например пока UI поток блокирован, ни один из потоков не сможет внятно обратиться к этому потоку, потому что все синхронные вызовы замерзнут. То есть, снаружи потока не будет способа отличить блокированый UI поток от потока который надолго завис в короутинах.
Здравствуйте, Ikemefula, Вы писали:
I>>>Ты лучше сделай наконец тот пример что я тебя просил. EP>>какой? тут уже было достаточно ликбез-примеров I>Понятно, аргументы закончились
алле, какой пример?
EP>>>>Вызывающий поток(thread) не блокируется, а возвращается к другим задачам, например по event loop. I>>>Для этого надо псать специальный код. EP>>Этот код пишется один раз, и едет библиотеку, при этом ни каркас приложения, ни event loop — не меняются. I>Ну это просто вранье. alex_public показал, как event-loop "не меняется" — путем встраивания RunAll в event loop или прикручивая таймер
Так я же выше показывал пример с полностью локальной трансформацией, без модификации event-loop
I>>>При этом await позволаяет включать ожидание там где тебе надо. EP>>Так и тут при необходимости можно явно указать где не нужно ожидание I>Продемонстрируй свой getline один раз с ожиданием, другой раз без ожидания. Надеюсь, ты не станешь эмулировать await путем параметризации gitline специальным потоком ?
Выше есть оба примера
A>>>>Т.е. вызывающий поток блокируется до тех пор, пока Result не будет вычислен? I>>>Именно так и он это называет асинхронщиной, потому что де в этом потоке будет выполняться какая нибудь другая короутина, EP>>Так ты определись — либо блокируется, либо "в этом потоке" I>UI поток заблокируется, потому что буст не знает про message pump.
Так он и не должен ничего знать про message pump. Я же выше показывал пример
I>В этом потоке будет чтото выполняться, при чем не ясно, как указать что именно должно выполняться.
У асинхронных операций есть callback'и принимающие продолжения, вот в этот callback и нырнёт наша корутина — event loop это никак не трогает — всё полностью локально
I>Представь себе либу, которая ничего про твои короутины не знает. У ней ровно один метод, как водится, блокирующий, это именно то ради чего нужна асинхронщина: I>http://rsdn.ru/forum/philosophy/5215721.1
То есть по твоему "асинхронщина" — это только выполнение в отдельном потоке?
Ничто не мешает закинуть post_event с unyield'ом корутины в конец нового потока Уже надоело объяснять банальные вещи
Здравствуйте, Ikemefula, Вы писали:
I>Остался один открытый вопрос — сделать так, что бы буст, наконец, узнал про message pump.
ты действительно не понял, что трансформация полностью локальная?
EP>>>Так ты определись — либо блокируется, либо "в этом потоке" I>>UI поток заблокируется, потому что буст не знает про message pump. В этом потоке будет чтото выполняться, при чем не ясно, как указать что именно должно выполняться.
Тебе что-то неясно != "UI поток заблокируется"
I>Например пока UI поток блокирован, ни один из потоков не сможет внятно обратиться к этому потоку, потому что все синхронные вызовы замерзнут. То есть, снаружи потока не будет способа отличить блокированый UI поток от потока который надолго завис в короутинах.
Почему завис на корутинах? Ты о чём?
Если в случае C# долгие операции будут выполнятся в отдельном потоке, и ожидаться по await:
await Task.Factory.StartNew(() => DoAction());
То и на stackful coroutines никто не заставляет всё пилить в одном потоке:
Неважно где будет выполнятся асинхронная операция — в отдельном потоке или позже в этом, главное чтобы была возможность присоединить продолжение в виде:
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Остался один открытый вопрос — сделать так, что бы буст, наконец, узнал про message pump.
EP>ты действительно не понял, что трансформация полностью локальная?
Я утверждаю, что ты показал эмуляцию асинхронщины, а не саму асинхронщину, то есть, синхъронный код с нелокальные переходами.
I>>>UI поток заблокируется, потому что буст не знает про message pump. В этом потоке будет чтото выполняться, при чем не ясно, как указать что именно должно выполняться.
EP>Тебе что-то неясно != "UI поток заблокируется"
Покажи каким образом буст узнает про message pump.
EP>Почему завис на корутинах? Ты о чём?
Очень просто. твой пример с getline именно это и демонстрирует. Если ты делаешь вызов с ожиданием, то надо РУКАМИ пнуть message pump. В С# это делает компилятор.
Если ты не согласен, напиши внятно, почему это не надо делать.
EP>То и на stackful coroutines никто не заставляет всё пилить в одном потоке: EP>
И снова торчит та самая асинхронщина, которая, как ты утверждал, нигде не торчит ?
EP>Неважно где будет выполнятся асинхронная операция — в отдельном потоке или позже в этом, главное чтобы была возможность присоединить продолжение в виде: EP>
То есть, делать все что может сделать компилятор, но руками.
Итого — одним сообщением ты взял все свои слова назад
В сухом остатке, так сказать, все по прежнему — все что надо, в С++ пилится и контролируется руками, в сигнатуре и коде торчит ровно то же, что торчит в C#.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
I>>Понятно, аргументы закончились
EP>алле, какой пример?
Да все тот же, где Sleep используется.
I>>Ну это просто вранье. alex_public показал, как event-loop "не меняется" — путем встраивания RunAll в event loop или прикручивая таймер
EP>Так я же выше показывал пример с полностью локальной трансформацией, без модификации event-loop
Тот где торчит asynchronous или тот где getline ? Если getline сам по себе, то он блокирует message pump и что бы это пофиксить, нужно научить буст запускать message pump.
I>>UI поток заблокируется, потому что буст не знает про message pump.
EP>Так он и не должен ничего знать про message pump. Я же выше показывал пример
Да, я в курсе, asynchronous.
EP>У асинхронных операций есть callback'и принимающие продолжения, вот в этот callback и нырнёт наша корутина — event loop это никак не трогает — всё полностью локально
То есть, вместо линейного кода на ровном месте получаются continuations
EP>То есть по твоему "асинхронщина" — это только выполнение в отдельном потоке?
Асинхронщина это обращение к некоторой сущности, у которой время отличное от времени центрального процессора. Все что ты показывал, это просто другая форма эвентов, т.е. все выполняется в одном процессоре а стало быть асинхронщины нет и быть не может, только эмуляция.
То есть, синхронный код с нелькальными переходами.
EP>Ничто не мешает закинуть post_event с unyield'ом корутины в конец нового потока Уже надоело объяснять банальные вещи
Ну да, лучше делать руками то, что может легко сделать компилятор