Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>И какой из них, на Ваш взгляд, следовало использовать в качестве официального термина в науке лингвистике?
Я предоставляют тебе право выбора. В какой из перечисленных категорий, на твой взгляд, слово "калька" было первым и не имело аналогов?
--
Не можешь достичь желаемого — пожелай достигнутого.
Так это новый виток в эре копроэкономики наступил, когда вместо грамотной технической документации в сеть выплевывается либо автоматически сгенерированная справочная информация, жиденько откомментированная специалистом, либо поток сознания в виде тех же proposal, написанных, как средневековые философские трактаты, с закосом на наукообразность. А в опенсорс это вообще модус операнди, ведь продукт с его использованием делает только капиталист. А твоя де факто обязанность как инженера — социализация внутри релевантной тусовки инженеров, и попутное выяснение актуальных измениний в проекте. Вобщем-то, так всегда было, но чем больше капитал использует квалифицированную рабскую силу (опенсорс), тем больше подразумевается, что "все эти хомячки-хакеры... им же только хавку регулярно подбрасывай, а они там уже сами в своем кругу разберутся, какую документацию, и в каком виде писать, и типа организовывать их не нужно".
причем здесь стекфул корутины в контексте обсуждаемой имплементации в С++ стеклесс ?
вообще все очень притянуто зауши учитывая что я за последние лет 10
и стекфул корутин не наблюдал в любом маломайски популярном или топ нейм продукте на С или С++
Здравствуйте, okman, Вы писали:
O>Всем привет!
O>Изучаю C++20. В целом все понятно, но одна вещь вызывает наибольшие затруднения — корутины.
Всё просто, если немного упростить с деталями:
реализуешь шаблон coroutine_traits с внутренней структурой promise_type — это объект который будет использоваться в функции использующей корутины для управления работой.
То есть при первом же вызове оператора корутин формируется структура для работы с ними.
Далее когда есть вызов:
auto res = co_await fnested(...);
и пусть при этом
TResult fnested(...)
тогда co_await преобразуется в (понятно, что move расставлены не корректно, но они для демонстрации передачи владением объекта в другой код)
auto fnested_awaiter = operator co_await(fnested(...));
auto rest_code = [std::move(fnested_awaiter), std::move(args)]() {
auto res = fnested_awaiter.await_resume();
...//Rest code
};
if(!fnested_awaiter.await_ready()){
//Suspend
fnested_awaiter.await_suspend(std::move(rest_code));
} else {
rest_code();
}
То есть вызывается вложенная функция и у результата этой функции спрашивается готов ли результат. Если он готов, то результат забирается через await_resume иначе просто остаток функции упаковывается в лямбду и через await_suspend говорится, что когда вложенная функция отработает надо вызвать нашу лямбду для продолжения выполнения нашей функции.
co_return ещё проще — он просто вызывает метод return_value для вашего promise_type.
Таким образом
T f(T1 a1, T2 a2 ...) {
auto res = co_await fnested(...);
co_return ...;
}
Собственно всё. Дальше Вы сами решаете как строить цепочки функций, как производить "просыпание" и т.п. В этом мощь. В отличии от C# вы тут можете выбирать ту модель которую считаете оптимальной.
Здравствуйте, landerhigh, Вы писали:
L>Не уверен насчет крутости. Пока сам не использовал всерьез, лишь игрался невсерьез. L>-Они stackless. Значит, yield'ануть из глубин вложенных вызовов функций не выйдет. L>+Они stackelss. Значит, оверхед по памяти ограничен и оверхед на переключение контекста должен быть минимальным L>Этот плюс, имхо, должен перекрывать минус на порядок.
И stackless и stackful хороши по-своему.
Stackful легко реализуются в виде библиотеки — см Boost.Coroutine. А вот stackless в виде библиотеки не очень, и не полноценно — смотри реализацию в Boost.Asio. Поэтому вполне логично добавить stackless в стандарт в первую очередь.
Другое дело что походу то что завезли в стандарт, оно не самое лучше из того что можно было сделать, а конкртено в том месте где они впипдюрили аллоцирование фрейма, которого могло бы не быть, и что открыло бы ещё больше zero-overhead вариантов использования. В частности даже stackless макро-реализация из Boost.Asio обошлась без аллокаций, и такой и должна быть реализация stackless здорового человека, ибо размер фрейма известен во время компиляции.
Точно также как и размер замыкания известен во время компиляции, и мы мыжем просто сохранить всё замыкание через автоматический вывод типа. Представь что вместо конкретного типа замыкания мы бы всегда получали std::function
Здравствуйте, х, Вы писали:
х>преобразуется в что-то вида:
Подскажи пожалуйста, они дали возможность сохранить корутину через её конкретный тип, или там до сих пор есть стирание типа вытекающие в аллокацию (которое было в ранних вариантах)?
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Подскажи пожалуйста, они дали возможность сохранить корутину через её конкретный тип, или там до сих пор есть стирание типа вытекающие в аллокацию (которое было в ранних вариантах)?
Всё типилизированно. Тут реальная обёртка текущая под clang.
Здравствуйте, х, Вы писали:
EP>>Подскажи пожалуйста, они дали возможность сохранить корутину через её конкретный тип, или там до сих пор есть стирание типа вытекающие в аллокацию (которое было в ранних вариантах)? х>Всё типилизированно. Тут реальная обёртка текущая под clang.
Вопрос не про типизацацию в плане безопасности, а про стирание типа, type erasure. Ибо я именно что стирание типа и наблюдаю — std::coroutine_handle, каковым оно и было в ранних версиях.
Если разные генераторы, с разным набором и колличеством локальных переменных можно сохранить в один и тот же тип — то это и есть стирание типов, которого по-хорошему быть не должно. То есть оно может быть опциональным, по-желанию, как и std::function для замыканий, но не долнжо быть единственным вариантом.
Здравствуйте, reversecode, Вы писали:
R>а как бы вы сделали симметричные стеклесс корутины без аллокации фрейма ?
Сабжевые ассиметричные.
Stackless корутины есть в Boost.Asio — https://www.boost.org/doc/libs/1_75_0/doc/html/boost_asio/reference/coroutine.html
Локальное состояние и номер состояния преобразуется в поля класса, просыпание в нужное состояние происодит свитчем. Конкретный экземпляр корутины это объект этого класса у которго есть operator(). Всё состояине известно на этапе компиляции, также как и у лямбды-замыкания, поэтому аллокация не нужна.
Более того, такая конструкция не только позвоялет избавится от аллокации, но также и копировать корутины — что по сути является fork'ом. Ещё круче, что их можно сериализировать.
Автор Asio даже предлагал свой вариант в стандарт, без аллокаций — http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4244.pdf
Но Microsoft видимо продавили свою версию, так как у них уже была своя реализация Они её ещё иногда называют "negative overhead abstraction", с аллокациями ага, негатив блин
ассиметричные стеклесс корутины легко реализуются на макросах
симметричные стеклесс корутины на макросах нельзя сделать, поскольку есть контекст
а вот стекфулл симметричные легко
поэтому в сабже и сделали динамическое аллоцирование фрейма, через который можно переключаться
Здравствуйте, reversecode, Вы писали:
R>ассиметричные стеклесс корутины легко реализуются на макросах R>симметричные стеклесс корутины на макросах нельзя сделать, поскольку есть контекст R>а вот стекфулл симметричные легко R>поэтому в сабже и сделали динамическое аллоцирование фрейма, через который можно переключаться
Имея конкретный тип ассиметричной корутины её можно аллоцировать на стэке, в поле другого объекта, либо напрямую в куче. Симметричные корутины можно реализовать поверх ассиметричных.
Для многих use-case'ов подходят ассиметричные корутины на стэке, либо вообще заинлайненые по самые помидоры. Например для генераторов типа Python'ского yield. Авторы же сабжа в таких случаях предлагают уповать на то что оптимизатор может выкинуть аллокацию — HALO (heap allocation elision optimization) — но это ганатированно не работает при сохранении корутины в поле другого объекта.
стекфулл корутины очевидно не добавили в стандарт не потому что они легко реализуются самостоятельно
а потому что необходимо будет описать что такое стек(вспоминая Полухина и его бектрейс)
а за этим потянется и расщирения стека и перемещение объектов по стеку не нарушая их состояния, наверняка у комитета от этого взрывался мозг
я бы сказал по этому стекфулл корутины не очень юзабельны в С++
следить ручками и глазками за размером стека и пытаться сразу же угадать сколько нужно аллоцировать памяти на очередной фрейм это
Здравствуйте, reversecode, Вы писали:
R>я бы сказал по этому стекфулл корутины не очень юзабельны в С++ R>следить ручками и глазками за размером стека и пытаться сразу же угадать сколько нужно аллоцировать памяти на очередной фрейм это
Вотчить хэндами и айсами за сайзом и аттемптить саппозинг эмаунта спейса...
Здравствуйте, reversecode, Вы писали:
R>стекфулл корутины очевидно не добавили в стандарт не потому что они легко реализуются самостоятельно R>а потому что необходимо будет описать что такое стек(вспоминая Полухина и его бектрейс) R>а за этим потянется и расщирения стека и перемещение объектов по стеку не нарушая их состояния, наверняка у комитета от этого взрывался мозг
Перемещение объектов по стэку у stackful корутин врядли кода либо будет, в общем случае это вообще не реализуемо, либо с очень жёсткими ограничениями на вызываемый код, что убьёт всё мощь stackful — ибо они могут работать и прыгать через сторонний код.
R>я бы сказал по этому стекфулл корутины не очень юзабельны в С++
Даже библиотечная реализация достаточно юзабельная.
А вот stackless не очень, поэтому если есть выбор лично я предпочту stackless реализацию в стандарте, так как stackful по сути уже доступна.
R>следить ручками и глазками за размером стека и пытаться сразу же угадать сколько нужно аллоцировать памяти на очередной фрейм это
Ну здесь очевидно непонимание, ибо следить и угадывать размер ручками не нужно и никто не предлагает, даже в макро-реализации stackless из Asio.
Размер фрейма любой функции тривиально известен во время компиляции. Глубина прыжков stackless корутин огранична scope'ом одной фукции, что в C++20, что в C#, что в Python, на то они и stackless. Поэтому и размер корутины, как и её конкретный тип легко может быть известен во время компиляции