Здравствуйте, Евгений Музыченко, Вы писали:
_>>Вместо явной передачи управление её стараются скрыть под капотом, более того внетреннее состояние тоже прячут.
ЕМ>Это все от того, что развитием C++ в основном уже давно занимаются люди, понимающие программирование, как "запись алгоритма средствами языка", а не как обеспечение выполнения нужных действий с нужной степенью понятности, эффективности, применимости и т.п.
Скорее всего вы просто сильно в стороне от многих задач, которые сейчас решаются на C++.
Здравствуйте, kov_serg, Вы писали:
_>Мне больше по душе постепенно исполняемы функции, чем сопрограммы(корутины). Они явно требую кванта исполнения, в отличии от "сопрограм" которые вызываются (где попало) в разных тредах, колбяках, без каких либо ограничений.
Так корутины (сопрограммы) именно такими и являются — последовательно исполняемыми. Никаких разных тредов и вызовов где попало здесь нет. Пока одна сопрограмма выполняется, другая ожидает (suspended). Отличие лишь в количестве "квантов".
--
Справедливость выше закона. А человечность выше справедливости.
Re[5]: В написании линейного кода, который прерывается сетью
Здравствуйте, so5team, Вы писали:
S>Вроде бы несколько лет назад на Хабре была статья от Антона Полухина, где он показывал, как stackless короутины можно перебрасывать с одного треда на другой: https://habr.com/ru/companies/yandex/articles/420861/
Конечно, многопоточность и корутины можно использовать и совместно, в разнообразных вариантах. В то же время многопоточность не является встроенным свойством корутин.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Так корутины (сопрограммы) именно такими и являются — последовательно исполняемыми. Никаких разных тредов и вызовов где попало здесь нет. Пока одна сопрограмма выполняется, другая ожидает (suspended). Отличие лишь в количестве "квантов".
Дело не в названии а в принипе работы. Кто определяет когда функция продолжит исполнение, кто следит за ресурсами, которые функции использует, какие гарантии, какие инварианты необходимо соблюдать для таких открытых функций?
Где это описано для корутин? Обычно нигде.
Здравствуйте, kov_serg, Вы писали:
R>>Так корутины (сопрограммы) именно такими и являются — последовательно исполняемыми. Никаких разных тредов и вызовов где попало здесь нет. Пока одна сопрограмма выполняется, другая ожидает (suspended). Отличие лишь в количестве "квантов".
_>Дело не в названии а в принипе работы.
Так я и говорю о принципе работы, а не о названии.
_>Кто определяет когда функция продолжит исполнение
Так же, как и в обычной функции — вызвающая функция продолжит выполнение после того как вызываемая вернёт управление. Просто с корутинами этот принцип может работать и в обратном направлении. А может не работать — зависит от вызывающей функции.
_>, кто следит за ресурсами, которые функции использует, какие гарантии,
Всё то же самое, что и с обычными функциями. И гарантии ни чем не хуже.
_> какие инварианты необходимо соблюдать для таких открытых функций? _>Где это описано для корутин? Обычно нигде.
Здравствуйте, kov_serg, Вы писали:
R>>Так корутины (сопрограммы) именно такими и являются — последовательно исполняемыми. Никаких разных тредов и вызовов где попало здесь нет. Пока одна сопрограмма выполняется, другая ожидает (suspended). Отличие лишь в количестве "квантов".
_>Дело не в названии а в принипе работы. Кто определяет когда функция продолжит исполнение, кто следит за ресурсами, которые функции использует, какие гарантии, какие инварианты необходимо соблюдать для таких открытых функций? _>Где это описано для корутин? Обычно нигде.
И я что-то не очень понимаю, о каких гарантиях ты говоришь.
Например, каких гарантий тебе не хватает в примере ниже?
#include <concepts>
#include <generator>
#include <iostream>
template <std::incrementable T>
std::generator<const T&> lazy_sequence(T t, size_t count) {
for (size_t i = 0; i < count; ++i)
co_yield t++;
}
int main()
{
for (auto t : lazy_sequence(1, 10)) // -> 1 2 3 4 5 6 7 8 9 10
std::cout << t << ' ';
std::cout << std::endl;
for (auto t : lazy_sequence('A', 26)) // -> A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
std::cout << t << ' ';
}
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>И я что-то не очень понимаю, о каких гарантиях ты говоришь. R>Например, каких гарантий тебе не хватает в примере ниже?
R>http://coliru.stacked-crooked.com/a/8c7737e8d549bffb
R>
R>#include <concepts>
R>#include <generator>
R>#include <iostream>
R>template <std::incrementable T>
R>std::generator<const T&> lazy_sequence(T t, size_t count) {
R> for (size_t i = 0; i < count; ++i)
R> co_yield t++;
R>}
R>int main()
R>{
R> for (auto t : lazy_sequence(1, 10)) // -> 1 2 3 4 5 6 7 8 9 10
R> std::cout << t << ' ';
R> std::cout << std::endl;
R> for (auto t : lazy_sequence('A', 26)) // -> A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
R> std::cout << t << ' ';
R>}
R>
Это слишком простой пример. Тут никаких особых гарантий не надо, т.к. они не используют общих ресурсов и даже не выделяют их для выполнения зачачи.
Простой вопрос кто должен выделять и освободлать ресурсы исполнитель или прораб тот кто поставил задачу должен предоставить ресурсы для её выполнения?
Здравствуйте, kov_serg, Вы писали:
_>Это слишком простой пример. Тут никаких особых гарантий не надо, т.к. они не используют общих ресурсов и даже не выделяют их для выполнения зачачи. _>Простой вопрос кто должен выделять и освободлать ресурсы исполнитель или прораб тот кто поставил задачу должен предоставить ресурсы для её выполнения?
Что-то не понимаю я тебя. Правила всё те же, что и для обычных функций. Ресурсы могут быть выделены вызывающей корутиной, а освобождаться в вызываемой, а может быть и наоборот. Но позаботиться об освобождении ресурсов, в добротной программе, должен тот, кто их выделяет. При необходимости можно использовать RAII. Только при чём здесь корутины вообще? Это общие правила, которые действуют в равной степени как для корутин, так и для обычных функций. До тех пор, пока язык гарантирует детерминированность времён жизни объектов, прикрутить RAII поверх этого не составляет никаких проблем.
Ну или набросай пример, который заставляет тебя сомневаться. А то так можно долго обсуждать, не понимая друг друга.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, kov_serg, Вы писали:
_>Это слишком простой пример. Тут никаких особых гарантий не надо, т.к. они не используют общих ресурсов и даже не выделяют их для выполнения зачачи. _>Простой вопрос кто должен выделять и освободлать ресурсы исполнитель или прораб тот кто поставил задачу должен предоставить ресурсы для её выполнения?
Ты сомневаешься, что вызываемая корутина корректно завершает время жизни своего внутреннего состояния? На счёт этого можешь быть спокоен (см. пример ниже). А с точки зрения вызывающей функции процесс практически тот же самый, что и при многократном вызове обычной функции. Просто для передачи управления используеся новое словечко co_await.
LVV>>А в каких задачах корутины ЕМ>Вы вроде не мальчик, должны были застать слово "сопрограмма", а туда же...
Слово-то я знаю с 70-х годов.
Задач не было реальных
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, rg45, Вы писали:
R>Ты сомневаешься, что вызываемая корутина корректно завершает время жизни своего внутреннего состояния? На счёт этого можешь быть спокоен (см. пример ниже). А с точки зрения вызывающей функции процесс практически тот же самый, что и при многократном вызове обычной функции. Просто для передачи управления используеся новое словечко co_await.
Дело как раз не в этом. То что вы показали это просто генераторы, итераторы. У них точка итерирования явная. Коротины же используются для описания асинхронных операций. Более того способ передачи им управления обычно скрыт.
Они могут вызываться внешним циклом планировщика, callback-ами (причем не факт что из основного потока).
Здравствуйте, kov_serg, Вы писали:
_>Дело как раз не в этом. То что вы показали это просто генераторы, итераторы. У них точка итерирования явная. Коротины же используются для описания асинхронных операций. Более того способ передачи им управления обычно скрыт. _>Они могут вызываться внешним циклом планировщика, callback-ами (причем не факт что из основного потока).
Нет, то, что я показал — это как раз пример использования корутин. Использование ключевого слова co_yield не оставляет возможности думать по-другому. А использованный в примерах std::generator — это просто стандартная обёртка, облегчающая работу с корутинами:
A std::generator generates a sequence of elements by repeatedly resuming the coroutine from which it was returned.
Само по себе использование корутин вовсе не означает обязательного использования асинхронных операций. Не нужно путать тёплое с мягким.
P.S. Возможно, в следующим примере использование корутин будет лучше заметно
Здравствуйте, rg45, Вы писали:
R>Нет, то, что я показал — это как раз пример использования корутин. Использование ключевого слова co_yield не оставляет возможности думать по-другому.
Хорошо. Как с вашей точки зрения должны смотреться минимальные требования к функции которая исполняется постепенно?
Здравствуйте, kov_serg, Вы писали:
_>Хорошо. Как с вашей точки зрения должны смотреться минимальные требования к функции которая исполняется постепенно?
Там к самой функции требования простые: она должна использовать какие-нибудь слова из следующих: co_yield, co_return, co_await. Плюс некоторые несложные ограничения.
Гораздо более сложные требования к типу возвращаемого значения. И чтоб успростить использование, в С++23 ввели std::generator, как стандартный возвращаемы тип корутины.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, LaptevVV, Вы писали:
LVV>А в каких задачах корутины вот прям супер — супер?
Конечные автоматы.
LVV>Чего раньше приходилось делать муторно и долго ?
Вот их, родимых, и приходилось делать. Как вспомню, так вздрогну.
Корутина — это же "просто" функция, которая позволяет сделать специальный return (co_yield в нынешнем стандарте), и при последующем вызове продолжить выполнение со следующей инструкции.
И вот это вот "просто" позволяет асинхронную логику лаконично реализовать в одной функции вместо развешивания лапши колбеков.
Пока второй вариант многословней. Но и надо понимать, что StateMachine однотипный для всех корутин. Заново его писать не придётся. Основная бизнес-логика сосредоточена в runMachine. Тогда как в первом примере логика больше перенесена в StateMachine.
Здравствуйте, sergii.p, Вы писали:
SP>Пока второй вариант многословней. Но и надо понимать, что StateMachine однотипный для всех корутин. Заново его писать не придётся. Основная бизнес-логика сосредоточена в runMachine. Тогда как в первом примере логика больше перенесена в StateMachine.
Я бы ещё добавил эквивалентный вариант с использованием std::generator для полноты картины: