Комментарии 28
// SingleValueSender - нестандартный концепт,
// проверяющий что сендер отправляет только 1 значение
template<class S>
requires SingleValueSender<S&>
task<SenderReturnType<S>::type> retry(S sender) {
for (;;) {
try {
co_return co_await sender;
} catch(...) {
}
}
}
Это конечно очень красиво (неочень), но это просто не может работать. После запуска корутина уже другая, нежели была до первого запуска. Подобный retry просто невозможен
Вот демонстрация: https://godbolt.org/z/P1oYeGn8W : )
это предполагает, что сендер это не корутина, плюс он не меняет состояние из-за старта, т.е. фундаментально неэффективно, так как зачастую операции не готовятся к тому, что их перезапустят и например переиспользуют память, либо просто после запуска удаляют ненужные теперь ресурсы
То есть концепты вообще не напрягают "sender auto begin" при чтении кода надо еще помнить кто переменная, кто концепт а кто просто тип и что там теперь прикопано. Движемся в сторону юридических документов с 100500 отсылками в другие документя, что бы трактовать что происходит надо быть в теме контекста (который не стоит на месте и постоянно эволюционирует)
Код с retry, это просто пример для демонстрации интеграции сендеров и корутин. Конечно retry в таком виде особого смысла не имеет. Цель была показать, что можно делать co_await сендера
Я смотрю они весь zerocost увели в такую вещь как compiletime. Теперь ты можешь на этапе компиляции сделать ну ОЧЕНЬ много вещей. Чуть ли не корутину собрать, что тебе только байтики скопировать нужно будет.
А в данной фиче всё упрётся в реализацию, увы.
С общим положением согласен.
Ну таймер это конечно дичь. Какой таймер, когда есть объекты синхронизации. Из общей практики я бы сказал цена такого пула это обслуживание очереди, обычно асинхронность это некая очередь или очереди. Если многопоточный пул, то ещё добавляется синхронизация доступа к очереди. И если пул динамический, то вот тут можно таймер, что если не успевается разгребаться очередь, то увеличивать пул потоков.
Для нормальной работы пула ещё нужно, чтобы типичные системные операции как работа с файлами, сокеты - использовались асинхронные варианты. Чтобы не было такого, что поток из пула пошёл писать в файл. Файлы это латентная операция. Это будет жопка, много таких операций приведут к небольшому увеличению пула.
В остальном вообще вопрос в другом. Создание потоков тоже не zero cost. А латентные операции хочется не делать на основном потоке, и уметь нормально отменять.
индустрия абсолютно единогласно независимо пришла к async/await
Во-первых, не вся (java, go), во-вторых, async/await - зло, потому что делит весь код на красные и синие функции. В тот же c# хотели завезти полноценные грин-треды, но сдались, потому что тогда в языке появится две асинхронные модели, а это путь к разброду и шатанию.
Красные и синие функции - это прохладные истории тех, кто разобрались только на треть как это все работает для тех кто не разобрался вообще.
Как ты их не называй - async это целиком своя отдельная модель которую с блокирующим кодом мешать нельзя напрямую. Будет для тебя код асинхронный генерироваться комплиятором не явно или ты будешь как в плюсах все делать сам - разницы нет никакой.
Async. Нельзя. Блокировать. Все, нет никаких "красных и синих".
Что на самом деле вторичный фактор. Первичный, конечно, сгенерировать стейт машины, пробрасывать шедулер/контекст/рантайм асинхронным функциям. И даже если это все делалось бы в ручную, все упрется в том что это все требует явного разделения между асинхронным и синхронным кодом. И чисто случайно, побочно, это и достигается "раскрашиванием" методов. Что является выгодным плюсом для тех кто хочет писать код не особо разбираясь что вообще происходит. От части бед их изолировали своим решением разработчики языка.
Статью эту я читал примерно когда Прайм ее обозревал, и на мой взгляд она вообще ни о чем. Если ты достаточно глубоко разобрался с тем, что же такое асинхронный код, то становится очевидно почему нужно идти на согласие с тем что если что-то async - то все async. А с тем что не async, нужно осознанно быть очень осторожным внутри асинхронного кода. И точно так же ясно почему синхронный код не может внезапно начать порождать async вызовы: никто ему магическим образом не начнет прокидывать рантайм, никто не будет магическим образом учитывать твое состояние и статус, никакой магии нет.
А корутины уже взлетели?
Эта штука будет работать если она есть и в одном и в другом коде? Эта ведь тот самый рефакторинг кода ( дорогой от которого пытались уйти) сервиса и сторонней библиотеки?
В нашем примере, если автор сторонней библиотеки предоставляет интерфейс, совместимый с std::execution
Вообще-то здесь сразу два "если":
если автор библиотеки выставляет наружу интерфейс для интеграции с использованным внутри библиотеки тред-пулом;
если этот самый интерфейс совместим с std::execution.
Можно предположить, что в большом количестве случаев все закончится еще на первом "если".
Конечно, однако наличие std::execution по крайней мере дает возможность авторам библиотек предоставить стандартный интерфейс. Со временем, если std::execution станет популярным в комьюнити, подключится сетевой эффект. Приведет ли это к большей совместимости открытого плюсового кода или нет сказать сложно, но при наличии стандартного интерфейса на это по крайней мере больше шансов
Например, стратегией может быть наличие affinity треда пушащего работу с каким-либо тредом внутри тредпула
Может проще было эту мысль выразить непосредственно на английском языке? Зачем этот жалкий транслит русскими буквами?
Мимопроходил... Учил кресты много лет назад в версии 98. Почитал статью, почитал каменты... Насколько ж далеко это всё зашло, я не понимаю процентов 70% того что тут обсуждается. Почему программы не стали настолько же лучше?
они зачастую пишутся на js и электроне потому что так быстрее, вжух вжух и готово, с дешевым мощным железом никто не хочет байтики считать и за миллисекунды бороться
есть ощущение, что с++ слишком популярен и стоит цель как-то усложнить порог входа..
std::execution принят в C++26 — пора знакомиться