Russian Qt Forum

Qt => Общие вопросы => Тема начата: Igors от Сентябрь 24, 2020, 13:47



Название: Корутины (модное слово)
Отправлено: Igors от Сентябрь 24, 2020, 13:47
Добрый день

Давеча услышал слово "корутина" и решил глянуть. Первая ссылка. (https://startandroid.ru/ru/courses/kotlin/29-course/kotlin/594-urok-1-vvedenie.html) Прыткий молодой человек там немало накатал, правда все время ссылаясь на богомерзкую жабу. Начал читать - ни хрена не понял

Цитировать
Перепишем код с использованием корутины и suspend функции:
   
launch {
    val url = buildUrl()
 
    download(url) //suspend function
 
    toast("File is downloaded")
}

Эта корутина не заблокирует поток, в котором будет запущен ее код. Т.е. его можно запустить даже в main потоке. Функция download загрузит файл в отдельном потоке, а toast будет выполнен только после того, как download отработает.
Ну ясно, download выполняется в др нитке. Но как это "не заблокирует поток" ??? Если toast должен быть выполнен строго позже download, то надо либо(синхронно)  ждать завершения download (и значит нитка стоит) - или (асинхронно) отдать упр-е в событийный цикл, имея ввиду что download "в процессе".

Ну первый вариант неинтересен, выходит второй. Но тогда кто (или как) вернет упр-е
на точку toast? И когда это случится? Типа по таймеру, нет больше др событий?

Поясните. Спасибо




Название: Re: Корутины (модное слово)
Отправлено: Racheengel от Сентябрь 24, 2020, 14:52
Думаю, те, кто "корутины" придумали, про слово "поток" и "процесс" в лучшем случае когда-то на 1 курсе слышали.
Потоки это же "очень сложно", ведь там есть "мютексы" (а это по уровню ужаса почти как "поинтеры").


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 24, 2020, 15:07
Думаю, те, кто "корутины" придумали, про слово "поток" и "процесс" в лучшем случае когда-то на 1 курсе слышали.
Потоки это же "очень сложно", ведь там есть "мютексы" (а это по уровню ужаса почти как "поинтеры").


Корутины придумали чтобы не превращать код в лапшу коллбеков или хендлеров эвентов (то, на что Игорс жалуется в соседней теме).
Вместо подписывания на сигнал readyRead, мы просто делаем асинхронный await device->bytesAvailable().


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 24, 2020, 15:17
Ну ясно, download выполняется в др нитке. Но как это "не заблокирует поток" ??? Если toast должен быть выполнен строго позже download, то надо либо(синхронно)  ждать завершения download (и значит нитка стоит) - или (асинхронно) отдать упр-е в событийный цикл, имея ввиду что download "в процессе".

Ну первый вариант неинтересен, выходит второй. Но тогда кто (или как) вернет упр-е
на точку toast? И когда это случится? Типа по таймеру, нет больше др событий?

Поясните. Спасибо

Когда вы пишите (на плюсах) download(url) - это синхронный вызов функции.
Когда вы пишеште (на плюсах) co_await download(url) - это асинхронный вызов корутины.
Ну или на питоне
Код:
async def download(url):
     ...

await download(url)
Ключевое тут то что download - это не функция, а корутина. Типа как функтор это не функция так и корутина это отдельная сущность. Корутины умеют сохранять свое текущее состояние и возобновлять исполнение позже.
Ключевой вопрос в том, что происходит, когда корутина сохраняет свое состояние. В с++20 на это ответа нет - можно (многословно) написать свои таски и промисы которые как-то осуществляют диспатч.
Типичный пример диспатча (например, await в питоне) - это возврат в эвентлуп. Когда вы делаете co_await device->bytesAvailable(), корутина отдает управление в эвентлуп, этот луп обрабатывает события; когда придет событие нашей корутины, управление передастся ей и она продолжит выполнение.
Можно и по-другому диспатчить, например, в разных тредах - см. пример https://en.cppreference.com/w/cpp/language/coroutines.
На практике я знаю 2 вида диспатча - это генераторы (когда корутина синхронно отдает последовательность значений) и возврат в эвентлуп.
О5 же cppref подсказывает что можно делать "ленивые" корутины - типа генератор одного значения. Ну окей, неясно зачем отдельная сущность но пусть будет.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 25, 2020, 13:41
Ключевой вопрос в том, что происходит, когда корутина сохраняет свое состояние. В с++20 на это ответа нет - можно (многословно) написать свои таски и промисы которые как-то осуществляют диспатч.
Типичный пример диспатча (например, await в питоне) - это возврат в эвентлуп. Когда вы делаете co_await device->bytesAvailable(), корутина отдает управление в эвентлуп, этот луп обрабатывает события; когда придет событие нашей корутины, управление передастся ей и она продолжит выполнение.
Можно и по-другому диспатчить, например, в разных тредах - см. пример https://en.cppreference.com/w/cpp/language/coroutines.
На практике я знаю 2 вида диспатча - это генераторы (когда корутина синхронно отдает последовательность значений) и возврат в эвентлуп.
Спасибо за разъяснения, понимаю что фичв "в процессе" и полной ясности ожидать не приходится. Пока больше ничего не читал, просто немного поразмышлял (ну правда без карандаша и блокнота  :)).

Если это фича поддерживаемая стандартной библиотекой то видимо "eventLoop" в ней участвовать не должен, т.к. либа о нем ничего не знает. Тогда не вижу др способа кроме такого
Код
C++ (Qt)
void Test( void )
{
 InitData();
 SomeCoRoutine()
 AnalyzeResults();
}
При выполнении этого кода main добирается до SomeCoRoutine, запускает задачу и... выходит из Test, ничего др разумного не видно. Когда задача отработала - main каким-то чудесным образом (пока неясно каким) возвращается на AnalyzeResults. Здесь неясно а что же с тем кодом что main молотила до волшебного возврата.

Насколько верны мои наивные предположения?  :)


Название: Re: Корутины (модное слово)
Отправлено: Old от Сентябрь 25, 2020, 15:04
Спасибо за разъяснения, понимаю что фичв "в процессе" и полной ясности ожидать не приходится.
В каком процессе?  ;D

Сопрограммы описывал еще Кнут в своей книге в 70-х годах прошлого века.

Библиотеки для "зеленых тредов" (без сохранения/восстановления контекста) были в C десятки лет.

Поддержка сохранения/восстановления контекста кучу лет доступно в бусте (boost.context), также есть поддержка в linux (man ucontext). У буста есть основаная на их context поддержка fiber (boost.fiber). Используя эти средства можно писать свои корутины с самыми замысловатыми планирощиками. Уже кучу лет в boost.asio есть возможность писать асинхронный код с использованием корутин, что действительно дает более читаемый и понятный код, по сравнению с колбечным.

Сейчас их просто добавили в стандарт. Будем надеятся у них это получиться хорошо. :)


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 25, 2020, 15:20
При выполнении этого кода main добирается до SomeCoRoutine, запускает задачу и... выходит из Test, ничего др разумного не видно. Когда задача отработала - main каким-то чудесным образом (пока неясно каким) возвращается на AnalyzeResults. Здесь неясно а что же с тем кодом что main молотила до волшебного возврата.

Насколько верны мои наивные предположения?  :)

Вся магия в операторе co_await который вы зачем-то опускаете. По факту это такой return из корутины с возможностью потом вернуться. Когда вы делаете co_await myCoroutine(), управление возвращается наверх создавая объект корутины который хранит стейт. Когда кто-то где-то позовет h.resume() (где h - хэндл корутины, std::coroutine_handle), управление передастся обратно этому коду и оно продолжится после co_await.
Вот чувак поигрался (http://jefftrull.github.io/qt/c++/coroutines/2018/07/21/coroutines-and-qt.html) с co_await кутешных сигналов.

Я добавил отладки чтобы было понятно куда идет control flow:
Код:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // a really simple widget
    ColorRect cr;
    cr.setWindowTitle("Color Cycler");
    cr.show();

    qDebug() << "before coro";
    // change widget color every 500ms
    QTimer * changeTimer = new QTimer(&app);
    auto ro = [&]() -> qtcoro::return_object<> {
        qDebug() << "entering coro";
        while (true) {
            qDebug() << "entering loop";
            co_await qtcoro::make_awaitable_signal(changeTimer, &QTimer::timeout);
            qDebug() << "awaited";
            cr.changeColor();
        }
    }();
    qDebug() << "after coro";

    changeTimer->start(5000);

    qDebug() << "entering exec()";

    return app.exec();
}
Выхлоп:
Код:
before coro
entering coro
entering loop
after coro
entering exec()
awaited
entering loop
awaited
entering loop
Как видно, после первого вызова co_await, мы вышли из лямбды и ушли в эвентлуп, когда таймер тикнул, мы вернулись в лябмду, сделали код после co_await и снова ушли в эвентлуп.
С тз Qt это выглядит так - мы спим в эвентлупе, тикает таймер, он дергает сигнал, тот вызывает слот, который делает handle.resume(), передавая управление в лямбду, выполняется лямбда, доходит до co_await, возвращаемся из handle.resume(), возвращаемся в эвентлуп.

Если у вас Xcode 12, то можно поиграться с его примерами, с минимальными изменениями проекта оно собирается с AppleClang


Название: Re: Корутины (модное слово)
Отправлено: Racheengel от Сентябрь 25, 2020, 18:58
Мда... какие-то адские танцы с бубнами вокруг новообразованных абстракций...
Чем не устраивает асинхронное выполнение в другом потоке?
Ну что то типа такого:

<тут мы в гуе>

auto downloadResult = start_in_another_thread(download(url));

... и пошло где-то там работать ...

show_wait_dialog();

while (!downloadResult.isDone())
   ... загрузка тянется, диалог обновляется ...
  update_wait_dialog(downloadResult.progress());

... тут поток кончился ...

close_wait_dialog();


Конечно, можно это и поэстетичнее оформить. Просто как правило людям нужно нечто простое для понимания и написания, типа там:

auto downloadResult = start_in_another_thread(download(url));  // это в один поток пошло

show_wait_dialog_with_progress(downloadResult);  // а это в другой (гуй), диалог висит и обновляется, пока первый поток жив


Название: Re: Корутины (модное слово)
Отправлено: Old от Сентябрь 25, 2020, 19:05
Чем не устраивает асинхронное выполнение в другом потоке?
А что будет делать текущий поток, пока в другом что-то выполняется? Просто ждать? :)

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


Название: Re: Корутины (модное слово)
Отправлено: Racheengel от Сентябрь 25, 2020, 19:09
А что будет делать текущий поток, пока в другом что-то выполняется? Просто ждать? :)

Нет, почему же, окошки обновлять, прогресс показывать, на мыш реагировать :)


Название: Re: Корутины (модное слово)
Отправлено: Пантер от Сентябрь 26, 2020, 13:40
Может, будет полезно, сегодня на статью наткнулся https://habr.com/ru/post/520756/?utm_source=habrahabr&utm_medium=rss&utm_campaign=520756


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 26, 2020, 13:41
Вся магия в операторе co_await который вы зачем-то опускаете.
По той простой причине что я не знал о его существовании :) Выходит он все и делает: запускает указанную задачу в др нитке и выходит из текущего блока кода (в скобарях). И он же гарантирует что по окончании задачи упр-е (в main) получит строка после вызова co_await.

Интересен момент обратной передачи упр-я, т.е. возврат на точку после co_await по окончании задачи. Ведь main может быть занят какой-то полезной работой (для этого все и городилось), и просто так прервать эту работу нельзя

Чем не устраивает асинхронное выполнение в другом потоке?
Ну что то типа такого:

<тут мы в гуе>

auto downloadResult = start_in_another_thread(download(url));

... и пошло где-то там работать ...

show_wait_dialog();

while (!downloadResult.isDone())
   ... загрузка тянется, диалог обновляется ...
  update_wait_dialog(downloadResult.progress());

... тут поток кончился ...

close_wait_dialog();
Типичный пример "бездумного запуска в др потоке" :) Если мы все равно "ждем-с", то надо было в main и выполнять, периодически вызывая processEvents, чем кстати и занимается QProgressDialog


Название: Re: Корутины (модное слово)
Отправлено: Пантер от Сентябрь 26, 2020, 14:00
Igors, я советую тебе взять Python3 и на его примере изучить, что такое асинхронное программирование. В плюсах как всегда все переусложнено.
И я вот не понимаю, тебе лень открыть документацию и почитать? Я думаю, даже викиучебника будет достаточно чтобы схватить основную идею, там все примитивно.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 26, 2020, 14:04
Igors, я советую тебе взять Python3 и на его примере изучить, что такое асинхронное программирование. В плюсах как всегда все переусложнено.
И я вот не понимаю, тебе лень открыть документацию и почитать? Я думаю, даже викиучебника будет достаточно чтобы схватить основную идею, там все примитивно.
Если я "схватил основную идею", то мне не составляет труда ее пояснить. А Вам?  :)


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 26, 2020, 14:06
Типичный пример "бездумного запуска в др потоке" :) Если мы все равно "ждем-с", то надо было в main и выполнять, периодически вызывая processEvents, чем кстати и занимается QProgressDialog

Нет никаких ниток, всё в одном потоке делается.
Считайте что co_await делает внутри setjump/longjump в разные куски программы, такой goto. Как оно "у ей внутре" устроено - вопрос отдельный, но логика примерно такая - она как-то сохраняет текущий фрейм и позволяет к нему вернуться.
+1 за питон - взять и написать простейшую качалку файлов на корутинах, задача часа на 2 из них час-полтора занимает чтение что такое корутины в питоне.
Я уже приводил пример, последовательный блокирующий код
Код:
def foo():
    ...

a = foo()
b = bar(a)
c = baz(b)

тривиально превращается в асинхронный:
Код:
async def foo():
    ...

a = await foo()
b = await bar(a)
c = await baz(b)


Название: Re: Корутины (модное слово)
Отправлено: Пантер от Сентябрь 26, 2020, 14:08
А я не хочу тратить свое время, чтобы объяснять элементарные вещи человеку, которому лень самому разобраться. Я с радостью делал это много раз для джунов, которые еще не умеют что-то самостоятельно выяснять, но ты-то не джун. ;) Не трать наше время, а иди и сам разбирайся.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 26, 2020, 14:18
Нет никаких ниток, всё в одном потоке делается.
??? Так быть не должно, это противоречит идее асинхронности

Считайте что co_await делает внутри setjump/longjump в разные куски программы, такой goto. Как оно "у ей внутре" устроено - вопрос отдельный, но логика примерно такая - она как-то сохраняет текущий фрейм и позволяет к нему вернуться.
Ну вот мы запустили корутину и продолжаем выполняться. Нужен longjump чтобы вернуться, но мы же его не пишем сами. Кто (и в какой момент) его аызывает/реализует?


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 26, 2020, 14:27
А я не хочу тратить свое время, чтобы объяснять элементарные вещи человеку, которому лень самому разобраться. Я с радостью делал это много раз для джунов, которые еще не умеют что-то самостоятельно выяснять, но ты-то не джун. ;) Не трать наше время, а иди и сам разбирайся.
Лично Вас я не приглашал, и ничего не хочу от Вас получить :) Также никаких планов юзать корутины у меня нет, просто интересно что за фишка такая модная и что она делает. Почему мы об этом не можем поговорить? И чего Вы злитесь?  :)


Название: Re: Корутины (модное слово)
Отправлено: Old от Сентябрь 26, 2020, 14:40
Нет никаких ниток, всё в одном потоке делается.
??? Так быть не должно, это противоречит идее асинхронности
Что за глупость?
Асинхронность и многопоточность это перпендикулярные понятия, никак не связанные. Может быть асинхронно в одном потоке и синхронно в разных.


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 26, 2020, 14:44
Ну вот мы запустили корутину и продолжаем выполняться. Нужен longjump чтобы вернуться, но мы же его не пишем сами. Кто (и в какой момент) его аызывает/реализует?

Компилятор, когда видит co_await. Он выделяет память (в куче) под текущий фрейм сохраняет туда контекст регистры что ему надо и делает setjump.
Когда где-то кто-то зовет handle.resume(), он восстанавливает данные из фрейма и делает переход в корутину (longjump).
Не факт что оно реализуется именно через эти функции, но я других способов не знаю, поэтому мне проще думать в терминах этих функций.
В целом, никто не мешает написать свой джамп, наверное.


Название: Re: Корутины (модное слово)
Отправлено: Old от Сентябрь 26, 2020, 14:50
Компилятор, когда видит co_await. Он выделяет память (в куче) под текущий фрейм сохраняет туда контекст регистры что ему надо и делает setjump.
Когда где-то кто-то зовет handle.resume(), он восстанавливает данные из фрейма и делает переход в корутину (longjump).
Не факт что оно реализуется именно через эти функции, но я других способов не знаю, поэтому мне проще думать в терминах этих функций.
В целом, никто не мешает написать свой джамп, наверное.
Бэкенд там очень простой, вот на примере ucontext небольшая демка: https://gist.github.com/DanGe42/7148946
В этом примере используются системные сигналы для прерывания сисколов и переключения контекста, но в самом простом случае достаточно одного swapcontext, он все и делает.


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 26, 2020, 14:55
Да, вы правы, есть более продвинутый набор функций https://ru.wikipedia.org/wiki/Setcontext


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 26, 2020, 19:29
Ну вот мы запустили корутину и продолжаем выполняться. Нужен longjump чтобы вернуться, но мы же его не пишем сами. Кто (и в какой момент) его аызывает/реализует?

Компилятор, когда видит co_await. Он выделяет память (в куче) под текущий фрейм сохраняет туда контекст регистры что ему надо и делает setjump.
Когда где-то кто-то зовет handle.resume(), он восстанавливает данные из фрейма и делает переход в корутину (longjump).
Не факт что оно реализуется именно через эти функции, но я других способов не знаю, поэтому мне проще думать в терминах этих функций.
В целом, никто не мешает написать свой джамп, наверное.
Вопрос был "кто (и в какой момент)", а не "как" - это действительно технические подробности второго плана. Судя по этому примеру
Код
C++ (Qt)
       while (true) {
           qDebug() << "entering loop";
           co_await qtcoro::make_awaitable_signal(changeTimer, &QTimer::timeout);
           qDebug() << "awaited";
           cr.changeColor();
       }
      ....
Упр-е возвращается на точку "awaited" при выходе (или попытке выхода) из области видимости co_await (тело while). Как если бы co_await вернула какую-то футуру и по окончании итерации while сработал бы ее деструктор. И вот там задача парится до упора и выполняется переход. Др вариантов здесь не видно, больше заставлять main прыгать просто некому. Но меня смущает что это нигде не написано  :'(

Понятно что должны быть и др средства для "ручного" упр-я, но тогда co_await должен какую-то цацку вернуть


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 26, 2020, 19:37
Нет, co_await просто делает выход из лямбды сразу же. Он создал объект корутины в куче (для дальнейшего продолжения), сохранил в этот объект контекст и вышел, передав управление обратно в main().
Когда сигнал дернул handle.resume() (смотрите гитхаб как реализован make_awaitable_signal), компилятор восстановил контекст и передал управление на инструкцию следующую за co_await (блин как бесит этот префикс co_, вот нельзя было сделать по-человечески)


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 26, 2020, 20:38
Нет, co_await просто делает выход из лямбды сразу же. Он создал объект корутины в куче (для дальнейшего продолжения), сохранил в этот объект контекст и вышел, передав управление обратно в main().
То "first pass"

Когда сигнал дернул handle.resume()..
Вот я и интересуюсь "когда" - само собой это ведь не случится если main продолжил нормальное выполнение после "first pass"

Др словами если main (поток создающий задачи) не блокирован (для этого все и городилось) - то значит он может делать что угодно, и никто "извне" не заставит его сделать переход


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 26, 2020, 23:05
Когда мы создали корутину, мы подписались на сигнал, который дернет resume(). Когда-нибудь. Может быть.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 27, 2020, 11:08
Когда мы создали корутину, мы подписались на сигнал, который дернет resume(). Когда-нибудь. Может быть.
Надеюсь это не "системный" сигнал линуха и не прерывание. А Qt сигналы и все остальное должны получить упр-е. Как оно к ним придет? Тот же фрагмент
Код
C++ (Qt)
      while (true) {
           qDebug() << "entering loop";
           co_await qtcoro::make_awaitable_signal(changeTimer, &QTimer::timeout);
           qDebug() << "awaited";
           cr.changeColor();
       }
 
Везде утверждается (и подчеркивается) что "создатель" (main) "не блокирован". Значит после создания он получит упр-е и перейдет к следующей итерации while.  И что, он будет хрюкать задачи бесконечно? Конечно нет, наоборот, фрагмент намекает что вся возня с таймером замкнута в теле while. Тогда кто инициирует "second pass"? Таймер (когда-то) дернет? А как он получит упр-е? Ведь пока мы крутим while - событийный цикл отрезан.

Здесь (http://jefftrull.github.io/qt/c++/coroutines/2018/07/21/coroutines-and-qt.html) неплохо описано, это тот самый случай что Вы говорите. Но это не согласуется с примером выше


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 27, 2020, 17:09
Внимательно посмотрите на вывод который я написал выше. Встретив co_await мы вышли из лямбды и ушли в эвентлуп. Никто не крутит цикл вечно, мы крутимся в эвентлупе пока не придет сигнал от таймера. Когда он приходит, мы возвращаемся в луп, делаем 1 итерацию, и снова выходим в кутешный эвентлуп. И так пока не надоест.
co_await не блокирует (как waitForFinished у QFuture), он отдает управление коду, вызвавшему корутину. На первой итерации это main(), на последующих - сигнал от таймера.


Название: Re: Корутины (модное слово)
Отправлено: Racheengel от Сентябрь 28, 2020, 10:08
Цитировать
Типичный пример "бездумного запуска в др потоке" Улыбающийся Если мы все равно "ждем-с", то надо было в main и выполнять, периодически вызывая processEvents, чем кстати и занимается QProgressDialog

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


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 28, 2020, 18:34
Внимательно посмотрите на вывод который я написал выше. Встретив co_await мы вышли из лямбды и ушли в эвентлуп. Никто не крутит цикл вечно, мы крутимся в эвентлупе пока не придет сигнал от таймера. Когда он приходит, мы возвращаемся в луп, делаем 1 итерацию, и снова выходим в кутешный эвентлуп. И так пока не надоест.
co_await не блокирует (как waitForFinished у QFuture), он отдает управление коду, вызвавшему корутину. На первой итерации это main(), на последующих - сигнал от таймера.
Да, так "все сходится", спасибо за разъяснения. Я неверно понял "не блокируется" - стало быть, упр-е возвращается вызывающему. В действительности main пошел заниматься др делами и вернулся только после того как задача выполнена.

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


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 29, 2020, 13:19
Ну хорошо, вот задача соседней темы (http://www.prog.org.ru/index.php?topic=32807.msg242759#msg242759) которая прямо напрашивается на корутину. Получив MousePressed мне нужно уходить в событийный цикл до тех пор пока не получу MouseMoved или MouseReleased, после этого продолжить обработку MousePressed

Как это сделать?


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 29, 2020, 14:10
по аналогии с подпиской на сигнал, только вместо коннекта надо вешать эвент фильтр из пробуждать корутину из него
детали мне неведомы я еще ни одной корутины на с++ не писал пока только читаю портянки кода других людей.
выкладывайте, будет интересно посмотреть


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 29, 2020, 15:27
выкладывайте, будет интересно посмотреть
Вы переоцениваете мой энтузиазм :) Я еще и до c++17 не дополз, а о с++20 нечего и говорить

по аналогии с подпиской на сигнал, только вместо коннекта надо вешать эвент фильтр из пробуждать корутину из него
Чего ж из фильтра-то? Напрашивается так
Код
C++ (Qt)
while (true)  {   // хз умеет ли возвращать
co_await IsMouseStillDown();
if (releaseMouseFlag) break;
 
А прыжки взад уже из фильтра. Но как я попаду в eventLoop из IsMouseStillDown ? Если тем же processEvents то все тот же головняк, "выйгрышь" никакой.

Да, и где Ваш молодой интересный друг? Для которого все "элементарно" (что кстати совсем не синоним "просто" как объяснял мне профессиональный математик).


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 29, 2020, 20:58
Очень годная лекция которая в целом отвечает на вопрос "а чо так сложна" https://www.youtube.com/watch?v=R_gZQJC-uv0


Название: Re: Корутины (модное слово)
Отправлено: Igors от Сентябрь 30, 2020, 15:38
Очень годная лекция которая в целом отвечает на вопрос "а чо так сложна" https://www.youtube.com/watch?v=R_gZQJC-uv0
Не очень ясно. Ну ладно, вот (редкий) светлый момент (аттач). Верно ли я понимаю что

auto t = foo();  // напечатает "Hello"
t.resume();       // напечатает "World"
t.resume();       // напечатает "World" еще раз

?



Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 30, 2020, 15:53
Нет, это он приводит пример корутины которая не начинает сразу "рваться в бой" а стопается сразу при входе в неё (https://youtu.be/R_gZQJC-uv0?t=2047)
Код:
auto initial_suspend() { return std::suspend_always(); }

Поэтому чтобы начать ее исполнение надо позвать resume() в первый раз. В примере который мы рассматривали выше (с сигналами) initial_suspend не тормозил корутину.
Зачем такое нужно? Например "ленивые" вычисления - вы отдельно создали корутину, а исполнили ее код когда-нибудь потом, когда она реально понадобится.


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Сентябрь 30, 2020, 16:18
Код:
auto t = foo();  // не делает ничего, просто создает объект корутины (окей, это относительно тяжелая операция)
t.resume();       // напечатает "hello"
t.resume();       // напечатает "World"


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 01, 2020, 12:15
Да, лектор поясняет этот момент через неск секунд после того как я "иссяк" :) Сегодня досмотрел до конца, во второй раз пошло значительно легче.

Выходит "корутины" - это по сути возможность выполнить не всю ф-цию, а ее часть/кусок. Само по себе это никак не связано с асинхронностью, фоновым выполнением и.т.п. Еще раз тот же кусок кода
Код
C++ (Qt)
while (true) {
  qDebug() << "entering loop";
  co_await qtcoro::make_awaitable_signal(changeTimer, &QTimer::timeout);
  qDebug() << "awaited";
  cr.changeColor();
}
Да, "не блокируется", просто в строке co_await происходит return (специфический), а строка awaited выполнится когда корутину опять позовут, кто и когда - дело вызывающего.

Вернемся к драгу. Получается ф-ция драга должна быть корутиной (не очень удобно, это член класса), а вызывать ее должны все обработчики "пожираемых" событий, напр
Код
C++ (Qt)
bool MyFilter::eventFilter( QObject * obj, QEvent * e )
{
  switch (e->type()) {
    ...
    case QEvent::MouseMoved:
      m_drag.resume();
      return true;
   ...
  }
}
Где m_drag - член класса фильтр, хендл на корутину, как его делать - не знаю, найду подобное и перепишу. Теперь сам драг
Код
C++ (Qt)
void MyDrag( void )
{
...
while (true) {
 ...
 co_yield;    // ждем пока не вызовет одно из событий
 
// тело драга
 QPoint pt = GetMousePosition();
 if (pt == oldPt) continue;
 DoDrag(pt);
 oldPt = pt;
}
}
}
Верно ли я мыслюсь?  Если да, то как передать в корутину QEvent * e ?


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 05, 2020, 11:01
По поводу лекции - это ужасно. Во-первых, ничего не дается "под запись", чуть прощелкал, потерял нить - и пиши пропало :'( Хотя я сам записывать никогда не любил, но все же... на момент лекции человек может совсем не гореть жаждой знаний, отягощен др впечатлениями и.т.п. И он остается "за бортом" - это не есть хорошо.

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

Ладно, посмотрим как получить хендл чтобы звать resume, без этого не обойтись. Лектор говорит
Цитировать
Нужно реализовать простейший тип resumable вот для этого
А нафиг оно мне надо, что-то там реализовывать? Готового нету, что ли? Мне юзать надо, а не вдаваться в нюансы :)


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Октябрь 05, 2020, 15:41
По поводу лекции - это ужасно. Во-первых, ничего не дается "под запись", чуть прощелкал, потерял нить - и пиши пропало :'( Хотя я сам записывать никогда не любил, но все же... на момент лекции человек может совсем не гореть жаждой знаний, отягощен др впечатлениями и.т.п. И он остается "за бортом" - это не есть хорошо.

Чувак же неоднократно говорил что запись будет на ютубе, что непонятно, можно пересмотреть. Я вообще смотрю видео на скорости 1.5 потому что люди оч медленно говорят. А почитать очередной слайд можно и на паузу нажать.

Во-вторых, неплохо бы сразу пояснить о чем речь вообще, "за что боремся".
За что борются классы в с++? За что борются шаблоны? Разработчики шаблонов вредил могли подумать о том что люди будут использовать их в метапрограммировании, они задумывались как "генерики".
Примеров использования корутин масса, некоторые он перечислил - генераторы, бесконечные последовательности, ленивые вычисления. Многое из этого есть в питоне, да даже в убогом TCL есть корутины. Серьезно, пощупайте питон, генераторы, async/await.
Основная идея - это "линеаризация" асинхронного кода так чтобы он выглядел синхронно - на каждом "синхронном" вызове мы просто уходим в эвентлуп и возвращаемся когда пришло нужно событие. Вместо лапши хендлеров эвентов, коллбэков или сигнал-слотов получаем простую последовательность действий как если бы мы писали синхронно. Но ожиданий и блокировок нет - код максимально производительный. Всё это требует поддержки библиотеками, конечно, boost asio и QTcpSocket придется переписать.

Отот пример (скрыншот выше) надо дать сразу - мы можем "входить в ф-цию", и это круто.  Не понимая этого главного я долго "плавал" не врубаясь о чем речь. Еще и бросает издевательские фразы типа "пользоваться корутинами очень легко". Ну и показал бы если "легко". Хотя это совсем не так, вот примерчик кончился, первая самостоятельная попытка с драгом - и тишина.
У меня есть более интересная задача - написать клиент к qbs session на корутинах. Но даже на мою задачу у меня нет времени/желания (я лучше прибухну и в комп поиграю), а вы хотите "готовое и на блюдечке".

Ладно, посмотрим как получить хендл чтобы звать resume, без этого не обойтись. Лектор говорит
Цитировать
Нужно реализовать простейший тип resumable вот для этого
А нафиг оно мне надо, что-то там реализовывать? Готового нету, что ли? Мне юзать надо, а не вдаваться в нюансы :)

Есть https://github.com/lewissbaker/cppcoro, что-то должно войти в станларт с++23. Но, понятное дело, Qt там не уважают (точнее, Qt не делает ровно ничего чтобы пихать свои наработки в стандарт - у них даже есть чел в комитете но никто не обращался к нему с пропозалом или идеей что-либо стандартизовать), так что связку придется писать самому в любом случае. Ну или подождать 5 лет когда Qt снизойдет до поддержки с++20. Ну как QList::toStdVector только посложнее.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 05, 2020, 23:59
Примеров использования корутин масса, некоторые он перечислил - генераторы, бесконечные последовательности, ленивые вычисления.
Всю жизнь делали примерно так (псевдокод)
Код
C++ (Qt)
value = FindFirst(&findData);
while (!value.IsEmpty()) {
 ProcessValue(value);
 value = FindNext(&findData);
}
 
Да, надо таскать с собой "контекст" (findData), ну или делать его членом класса. Это доставляет известные неудобства, но от этого еще никто не умирал. Корутина позволяет держать этот контекст в локальных переменных на стеке самой корутины. Интересная возможность, но я бы ее не переоценивал. Напр с multithreading видимо будут неприятности, стек-то не "размножить" по числу ниток (а вот findData пожалуйста). Зачем делать генератор или lazy на корутинах? Какой "выйгрышь"? Не вижу. Ну так, для понту разве что. И членом класса корутина видимо быть не могет (неприятно). И переключение стека может оказаться совсем не безобидно для пресловутой производительности.

Вместо лапши хендлеров эвентов, коллбэков или сигнал-слотов получаем простую последовательность действий как если бы мы писали синхронно. Но ожиданий и блокировок нет - код максимально производительный.
Не связано это никак с производительностью. Да, бывают случаи когда "дробление" кода сильно достает (пример с драгом), но не так уж часто. Можете привести пример без событийного цикла где корутина "в масть"? Вот я затрудняюсь.

Ну ладно, так как же оформлять корутину? Вот ссылка (https://blog.panicsoftware.com/your-first-coroutine/) не хуже остальных что я видел. Пишут
Цитировать
resumable foo(){
  std::cout << "Hello" << std::endl;
  co_await std::experimental::suspend_always();
  std::cout << "Coroutine" << std::endl;
}
Опять надо рисовать какой-то resumable. Не смертельно, надо так надо, но откуда вытекает такая необходимость? Тем более для либы где с десяток вариантов замены цикла for (для эстетов). А тут ни хрена нету, чего это ?

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


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Октябрь 06, 2020, 12:21
Всю жизнь делали примерно так (псевдокод)
Этот код все такой же синхронный - пока вы крутите этот луп вы не можете заниматься другими делами (не привлекая треды). Вообще файловое ИО пример отвратительный, так как в том же линуксе нет неблокирующего файлового ака completion port - вам надо самому городить огород на тредах чтобы их реализовать.
Сокеты - другое дело - пока вы "ждете" нового чанка данных, вы можете "ждать" чанк на другом сокете или новых клиентов. И вам не нужны треды и все проблемы связанные с ними - вы пишите такой же последовательный код как при блокирующем ИО но он магически становится неблокирующим за счет простого использования co_await (await в питоне)

Напр с multithreading видимо будут неприятности, стек-то не "размножить" по числу ниток (а вот findData пожалуйста).
На cppreference пример с resume() в другом треде, на хабре  (https://habr.com/ru/post/521058/)пример с консьюмером\продьюсером (правда у него там рейс о чем я ему сообщил в комментариях, там же более (не вглядывался) правильный вариант).
Но это всё обычно не нужно! Треды придумали не от хорошей жизни а от того что корутин не было.
Треды - вытесняющая многозадачность (ОС решает за вас когда переключать контекст). Корутины - кооперативна многозадачность, когда переключать контекст решаете вы сами. Как минимум плюс в том что контекст можно переключать реже. Например, я в Яндексе написал качалку на питоне (когда asyn/await еще не было) на "зеленых" тредах - 10к файлов качала за полчаса, тупая реализация "в цикле" без тредов имела ETA около недели. То есть без системных потоков можно получить тот же результат что и с ними, только не надо ничего синхронизовывать. Профит! Конечно, оба подхода можно комбинировать.

Зачем делать генератор или lazy на корутинах? Какой "выйгрышь"? Не вижу. Ну так, для понту разве что.
Примерно такой же как между функтором и лябмдой - писать меньше. Да, вы можете написать итератор который хранит std::function, сами делать сохранение контекста и переход к следующей "итерации"... А можно просто написать yeild в цикле.

И членом класса корутина видимо быть не могет (неприятно). И переключение стека может оказаться совсем не безобидно для пресловутой производительности.
Кто вам сказал? Обычная функция, просто return type специфический.
Переключение контекста в тредах больше + нужна синхронизация, а тут не нужно.

Не связано это никак с производительностью. Да, бывают случаи когда "дробление" кода сильно достает (пример с драгом), но не так уж часто. Можете привести пример без событийного цикла где корутина "в масть"? Вот я затрудняюсь.
Вы можете потратить больше времени на оптимизацию, так как оно освободилось потому что не надо писать лапшу коллбеков. Пайплайн лучше видно.

Ну ладно, так как же оформлять корутину? Вот ссылка (https://blog.panicsoftware.com/your-first-coroutine/) не хуже остальных что я видел. Пишут
Цитировать
resumable foo(){
  std::cout << "Hello" << std::endl;
  co_await std::experimental::suspend_always();
  std::cout << "Coroutine" << std::endl;
}
Опять надо рисовать какой-то resumable. Не смертельно, надо так надо, но откуда вытекает такая необходимость? Тем более для либы где с десяток вариантов замены цикла for (для эстетов). А тут ни хрена нету, чего это ?

Ну не успели стандартизовать библиотеку для корутин. Скажите спасибо что основную машинерию дали и теперь люди могут играться с ними - глядишь новые юзкейзы (которых нет в cppcoro) откроют.
Простейшие случаи (generator, lazy) будут в следующем стандарте, сейчас можно юзать cppcoro и не париться - возвращаете generator, пишите цикл с co_yeild и вуаля.
В остальном необходимость писать resumable проистекает из расширяемости и настраиваемости. В питоне вы не можете написать lazy (там вообще корутины не расширяемые), а на плюсах - можете. async/await ждали десяток лет, они работают только с эветлупом. Продьюсер-консьюмер на тредах с корутинами вы не напишите в питоне, а на плюсах - запросто. И тд...


Название: Re: Корутины (модное слово)
Отправлено: Old от Октябрь 06, 2020, 12:38
Но это всё обычно не нужно! Треды придумали не от хорошей жизни а от того что корутин не было.
Ну перестаньте. :)
Треды и корутины перепендикулярные понятия. :)
Вытесняющая многозадачность появилась в семидесятых, а "зелеными" тредами можно было пользоваться всегда.
Те кому были нужны или интересны корутины пользовались ими уже много лет. То что их добавили в стандарт C++20 не делает из них чего-то чудесного. :)


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 06, 2020, 18:14
Треды придумали не от хорошей жизни а от того что корутин не было.
Треды - вытесняющая многозадачность (ОС решает за вас когда переключать контекст). Корутины - кооперативна многозадачность, когда переключать контекст решаете вы сами.
"Треды" позволяют задействовать все ядра, а корутины сами по себе к этому никакого отношения не имеют, это просто (лихой) способ передачи упр-я, но в рамках одной нитки. Чисто на корутинах ничего не ускорить, ничего не "разпоточить".

И вот важный момент. В примере с драгом корутина смотрится гораздо выгоднее чем вторичный eventLoop с помощью processEvents. НО основные проблемы (которые жрут 95% времени) все те же. В любом случае упр-е отдается "в неизвестность", и что там произойдет - хз. Напр замочили структуры куда корутина пишет. Часто это охраняют модальным диалогом (товарищ в этой теме упоминал). Хотя какая тогда это многозадачность?
Цитировать
-Папа, папа, а что такое многозадачность в Вындоуз?
- Подожди, сынок, вот дискета отформатится и покажу
Или замыкать фоновую задачу так чтобы она ни с кем не конфликтовала. Но головняк остается - и капитальный. Напр вот баг который я так до конца и не исправил:

- Есть окно, отображает содержимое загруженных данных в виде списка. Юзер решает их перегрузить данные из файла. Ладно, грузим файл, показываем модальный прогресс. И вот в процессе загрузки прорывается событие рисования окна (хотя setUpdatesEnabled = false). Конечно оно лезет к "недогруженным" данным и вылетает. И что делать? "Надо было загрузить данные в др место, а по окончании загрузки все заменить". Так это может оказаться нереальным, да и трудоемкость такого решения очевидна.

Поэтому я бы все-таки корутины не переоценмвал. И, простите мою навязчивость, но все же
Можете привести пример без событийного цикла где корутина "в масть"? Вот я затрудняюсь.



Название: Re: Корутины (модное слово)
Отправлено: Авварон от Октябрь 06, 2020, 18:24
Поэтому я бы все-таки корутины не переоценмвал. И, простите мою навязчивость, но все же
Можете привести пример без событийного цикла где корутина "в масть"? Вот я затрудняюсь.



Уже приводил 2 раза - генератор, lazy, продьюсер-консьюмер.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 07, 2020, 09:50
Уже приводил 2 раза - генератор, lazy, продьюсер-консьюмер.
Ну они мне не кажутся столь убедительными как с событийным циклом. Скорее "лямбда вместо функтора" - да, возможно/иногда получше, поудобнее, но не более того.
Ну ладно, я ведь тоже не знаю убедительных, так что претензий нет  :)

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


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Октябрь 07, 2020, 12:03
генераторы - это очень прикольно, они позволяют экономить память - сейчас вы жонглируете временными векторами с кучей аллокаций и тому подобного, в питончике же можно оперировать над исходным контейнером "лениво" - это начинает ролять когда вы жонгируете гигабайтными матрицами.


Название: Re: Корутины (модное слово)
Отправлено: AkonResumed от Октябрь 18, 2020, 18:15
Как уже здесь многие отмечали, концепции этой "корутины" уже сто лет в обед. Мейнстрим практика - например, в Win32 API, начиная с NT 3.51, есть функция CreateFiber (читай корутина), которая в свою очередь создавалась с целью облегчения портирования Unix-овых программ под Windows. Соответственно, в Unix-ах это API появилось ... даже не знаю когда.

Востребованность? А часто ли требуется ручное переключение контекста? Часто ли вы использовали setjump/longjump? Ну если только вы пишите специфичный инструментарий, манипулирующий контекстом, например, такой как обработка исключений (есть разные реализации, в т.ч. через setjump/longjump).


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 19, 2020, 12:48
Востребованность? А часто ли требуется ручное переключение контекста? Часто ли вы использовали setjump/longjump? Ну если только вы пишите специфичный инструментарий, манипулирующий контекстом, например, такой как обработка исключений (есть разные реализации, в т.ч. через setjump/longjump).
По-моему другая крайность - недооценка. Как Вы делаете драг? Наверное корутиной - ведь Вам это давно известно? Или "спагетти" с 3 событиями? Или мучаетесь с processEvents как я? Думаю что ответа не последует :)

Др случаи эффективного применения тоже найдутся, пусть они не так уж часты. Напр конечные автоматы/пулеметы или синтаксический разбор.

Как уже здесь многие отмечали, концепции этой "корутины" уже сто лет в обед.
Так приходит старость :)


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Октябрь 19, 2020, 14:15
пусть они не так уж часты.

вся асинхронка? сетевое взаимодействие, доступ к БД. Вас не напрягает что QSqlDatabase блокирующий?


Название: Re: Корутины (модное слово)
Отправлено: AkonResumed от Октябрь 19, 2020, 23:26
Цитировать
По-моему другая крайность - недооценка.
Возможно, лет через 5 увидим.

Драг бы делал на событиях. Собственно, у нас событийная модель программирования, а вы переходите опять к последовательной, в которой эти события все равно должны обрабатываться по ходу последовательности.

processEvents(): навскидку, нужно запилить свой эвент диспатчер (наследник QAbstractEventDispatcher), который будет иметь режим извлечения и обработки событий поштучно, т.е. QAbstractEventDispatcher::processEvents() будет извлекать одно событие и возвращать управление. По MouseRelease будет возможность завершить драг перед обработкой последующих событий, например, Esc keypress, которое в противном случае отменило бы завершившийся драг.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 20, 2020, 10:47
Вас не напрягает что QSqlDatabase блокирующий?
Цитировать
- Ну как я играл ?
- В общем хорошо, но почему Вы не сделали ни одного хода конями?
- Так я не знаю как они ходют
Никогда не имел дела с QSqlDatabase, ни с др СУБД (хотя наверное скоро буду знакомиться). Все же рискну утверждать что этот пример ничего нового не вносит - ну опять-таки эффективный/удобный уход в событийный цикл, что есть - то есть.

Драг бы делал на событиях.
Не понял, что значит "бы"? Не представляю как Вам удалось отмазаться от этой работы, которая в UI всегда есть.
Собственно, у нас событийная модель программирования, а вы переходите опять к последовательной, в которой эти события все равно должны обрабатываться по ходу последовательности.
Даже чисто концептуально гораздо более естественно представить/трактовать драг как единое действие/акцию, которая и реализована должна быть одним методом/ф-цией. Эта операция имеющая начало и конец, да, в ходе ее запрашивается ввод юзера, и что, разве мы обязаны дробить код по обработчикам? Это вынуждает заводить "драговые" члены класса лишь с той целью чтобы напр в MouseMoved иметь то что было установлено в MousePressed и.т.п. Заметьте что мы сразу лишаемся возможности сделать общий класс драга, остается лишь как-то (коряво) наследовать окно. Число проблем лавинообразно нарастает с увеличением числа драгов в одном окне, мы вынуждены "свитчеваться" в каждом обработчике.

processEvents(): навскидку, нужно запилить свой эвент диспатчер (наследник QAbstractEventDispatcher), который будет иметь режим извлечения и обработки событий поштучно, т.е. QAbstractEventDispatcher::processEvents() будет извлекать одно событие и возвращать управление. По MouseRelease будет возможность завершить драг перед обработкой последующих событий, например, Esc keypress, которое в противном случае отменило бы завершившийся драг.
Если мы связываемся с processEvents, то тем самым уже признаем что хотим иметь 1 драг = 1 метод, т.е. последовательный код. Предложение перекрыть диспатчер мне кажется слишком смелым, все равно не видно как добиться "поштучной" выемки. Пробовал задействовать метод interrupt (вроде "оно"), но увы, "поштучных" событий он не гарантирует


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 21, 2020, 08:23
Ну ладно, вот мы (элегантно) "махнули хвостиком" и вышли из корутины в событийный цикл. При этом надеясь что рано или поздно упр-е вернется в корутину. А если нет? Ну где-то насвистели и кто-то сожрал тот же MouseReleased. И потом приходит MousePressed по которому корутина должна запуститься "с нуля". Что произойдет? И как бороться с такими коллизиями?


Название: Re: Корутины (модное слово)
Отправлено: ssoft от Октябрь 21, 2020, 17:58
Корутина - это объект с конкретным состоянием. Чтобы завершить корутину, достаточно удалить конкретный её экземпляр. Если необходимо запустить корутину "с нуля", то необходимо сформировать другой экземпляр корутины.


Название: Re: Корутины (модное слово)
Отправлено: Igors от Октябрь 22, 2020, 12:25
Корутина - это объект с конкретным состоянием. Чтобы завершить корутину, достаточно удалить конкретный её экземпляр. Если необходимо запустить корутину "с нуля", то необходимо сформировать другой экземпляр корутины.
Корректный, но какой-то "казенный" (неживой) ответ.
Цитировать
А можно пример?
:)


Название: Re: Корутины (модное слово)
Отправлено: Авварон от Октябрь 22, 2020, 14:39
легко:
Код:
{
    auto coro = getCoro();
    Q_UNUSED(coro);
}


Название: Re: Корутины (модное слово)
Отправлено: Painter от Январь 16, 2021, 22:41
У нас буржуи говорят, что это тупо сокращение от Code Routine и ничего больше
А это значит только одно -> код программы  ;D ;D ;D
Просто, знатоков "аглицкого" языка все еще "хватат"  ;)
А вообще-то прыткий молодой человек в самом начале сказал, что он ничего не понял и так оно и есть,
Речь идет о теории кодирования с научной точки зрения.