Корутины C++
Feb. 23rd, 2025 09:36 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
В С++20 появились корутины
Штука удобная, а стандарт написан так, что реализацию можно подставить какую хочешь. Это удобно. Но основная проблема - говорят, что человек может одновременно держать в голове 5..6 сущностей, программист - 7..8. Для реализации движка корутин нужно около 12.
Так с наскоку разобраться, как оно там под капотом работает, тяжело. Вроде все понятно, начинаешь делать - начинаются странности. При помощи ютуб - более-мене реально, но тоже сложно.
Я попытался сделать asyc/await движок с qt-шной очередью событий. (знаю про qcoro, но мне хочется понять, как оно сделано. А еще в qcoro нет await_all/await_first, и некоторые другие вещи не поддержаны). За 1 вечер нормально движок не сделать.
task<int> foo(){ ... }
int t = co_await foo();
int t = co_await foo();
Штука удобная, а стандарт написан так, что реализацию можно подставить какую хочешь. Это удобно. Но основная проблема - говорят, что человек может одновременно держать в голове 5..6 сущностей, программист - 7..8. Для реализации движка корутин нужно около 12.
Так с наскоку разобраться, как оно там под капотом работает, тяжело. Вроде все понятно, начинаешь делать - начинаются странности. При помощи ютуб - более-мене реально, но тоже сложно.
Я попытался сделать asyc/await движок с qt-шной очередью событий. (знаю про qcoro, но мне хочется понять, как оно сделано. А еще в qcoro нет await_all/await_first, и некоторые другие вещи не поддержаны). За 1 вечер нормально движок не сделать.
no subject
Date: 2025-02-24 09:19 am (UTC)Так ещё два вопроса. Передаём ли мы callback (тогда всё в порядке), или та корутина знает мои точки входа (тогда бардак, чисто с топологических соображений). Вот этот второй вариант и привёл меня когда-то к выводу, что лучше не надо.
Погуглил на вики. Да, я сильно против. Топология получается хреновая. Если что сломалось, то дыру не найти, вообще говоря.
no subject
Date: 2025-02-24 09:50 am (UTC)возможно, вопрос сформирован как-то некорректно. Я не понимаю, что спрашивается. Я попытаюсь ответить, но возможно это будет ответ невпопад:
В с++20 корутинах ты сам делаешь библиотеку(или готовую находишь), которая как тебе надо диспетчеризует исполнение по потокам, и в нужные момент зовет нужные континьюэйшены из нужных тебе потоков.
> Так ещё два вопроса. Передаём ли мы callback (тогда всё в порядке), или та корутина знает мои точки входа (тогда бардак, чисто с топологических соображений). Вот этот второй вариант и привёл меня когда-то к выводу, что лучше не надо.
Передать каллбэк можно, и работать будет, но это не часть механизма корутин. Я бы назвал каллбеки до-корутинным способом написания асинхронного кода.
Недостаток каллбеков в том, что когда у тебя много вложеных событий, то получается много вложенных каллбэкеов. И получается то, что назвали callback hell, и собственно ради отказа от callback hell эти корутины и придумали. В гугле вводите callback hell и тыкаете картинки, там будут примеры кода.
А если каждой асинхронной операции, например, нужен свой таймаут, а иногда таймаут нужен один на несколько операций, то там еще и ветвление асинхронное получается. Делал такое, больше не хочу. Это вообще жуть.
> Если что сломалось, то дыру не найти, вообще говоря.
На счет сишных корутин я не стану вообще ничего утверждать, т.к. почти не имел с ними дел, а только предварительно ознакомился. В kotlin корутины сделаны удобно, и библиотека уже есть. Я вообще не представляю, как сложно бы было некоторые вещи без них делать, но сама концепция вроде похожа на сишные.
Как таковой с++, даже без корутин, отлаживать мне тяжелей чем java/kotlin, поэтому понятно, что и с корутинами тоже будет тяжелей. Но если где-то какой-то баг понадобится искать - ну мне кажется, оценочно, что это так же тяжело будет, как и вообще все на с/с++. Поэтому я больше джаву-котлин люблю.
no subject
Date: 2025-02-24 11:43 am (UTC)Получаются обычные spaghetti. Которые нельзя алфавитно-топологически отсортировать. В которых может произойти бага, которую и теоретически невозможно локализовать. Это будет бюрократия, где не найти концов. (У нас в конторе примерно такая хрень, но у нас у разных групп сервисов репутации очень разные, и всегда можно свалить на "тех идиотов".)
no subject
Date: 2025-02-24 01:39 pm (UTC)да вроде наоборот оно задумывалось для "расспагечивания".
Наверное, или вы недопоняли суть, или я недопонял масштаб проблемы :)
Ну вот например, есть кнопка, и надо скачать последовательно 5 картинок с таймаутом. И если на кнопку нажали, то надо отменить скачку текущей скачиваемой картинки.
даже без кнопки и без таймаутов псевдокод построенный на каллбеках будет выглядеть условно так
Это будет отправной точкой. Теперь, чтобы добавить таймауты, их придется каждый раз подписывать-отписывать, и то же самое с кнопокой. Плюс навешивать событие по таймауту/кнопке отписывающее текущую скачку и начинающее следующую. Я даже не возьмусь это описывать псевдокодом: тупо много писанины.
Корутины все "выравнивают" и ты пишешь как будто код последовательный:
А когда надо навесить таймауты и кнопки - то используешь комбинаторы:
При этом комбинатор "точтозавершится_первым", запускает все 3 процесса сразу, но при завершении кого-то одного, остальные два процесса отменяются.
Из кода пропадает вот эта вложенность, события, подписки-отписки: избавляемся от вот этих самых spaghetti, которые все так не любят. И сразу становится видно, что именно делаешь. Поэтому количество багов уменьшается.
При этом предполагается, что либу поддержки корутин ты 1 раз отладил и забыл.
no subject
Date: 2025-02-24 01:47 pm (UTC)no subject
Date: 2025-02-24 02:36 pm (UTC)предполагается, что "скачать" возвратит байтовый массив, или какой-то объект с картинкой. таймаут возвратит void, в простейшем случае. нажатие кнопки - в простейшем тоже возвратит void, ну или например возвратит, правой или левой кнопкой мышки нажато.
И вот оно общение: я прошу "дай картинку" - а мне через какое-то время ее возвращают, или говорят "сорри, таймаут/кнопка отмены". Но при этом код я пишу, как будто последовательный, что существенно его упрощает и делает наглядным.
Чуть сложней дело обстоит с генераторами. Их вроде доделали полностью в с++23. А может и в 20, точно не скажу.
Вы вроде скалу знаете? Помоему в скале генераторы есть - но я не уверен. Когда-то очень давно читал книжку по скале - но не более того. Генератор это почти то же самое, что поток данных, только каждая следующая порция данных приходит через неопределенное время. Условно псевдокод:
no subject
Date: 2025-02-24 02:53 pm (UTC)Still, it's all pretty innocent. Not the kind of coroutines I knew, where entities call each other with no control regarding who can call whom (and why).