Комментарии 22
Такое впечатление, что разработчики стандартов C++ решили ещё раз пройтись по всем граблям, накопленным в программировании. Параллельный JCL вот придумали. Дальше они лет через 5 поймут, что очень редко реальный поток вычислений можно выразить графом, и революция закончится.
Концепция сама по себе привлекательная, но испытания практикой не выдерживает. Причём это известно уж лет 40, но очередные первопроходцы на этом славном пути не переводятся (каюсь, и сам был таким; у меня дипломная работа посвящена, а два выполненных проекта - касаются графовой модели комплексирования вычислительных процессов).
В принципе, весь сок из этого подхода был выжат Засыпкиным в 1989 году в его диссертации "Алгоритмы планирования на вычислительных моделях" (к сожалению, не имею чести быть знакомым с этим умнейшим человеком лично). Там прямо вот это всё, о чём статья. Только на Фортране-77, вроде. И автоматически строится, а не руками.
При этом в стандартной библиотеке всё еще нет ведения логов, и, помечтаем, сетевых коммуникаций хотя бы на уровне сокетов.
Так все ровно для более-менее серьезного проекта придется свое дописывать, если понадобиться реализовать, например сетевой троттлинг, реконнекты и пр, и так или иначе нужен доступ к нативному сокету.
Стандарт тупо ещё не умеет работать с юникодом, с файлами в разных кодировках. Потом уже будет сеть и всё остальное.
Последние несколько лет пишу на Rust вместо C++, и теперь, каждый раз, когда краем глаза слежу за развитием плюсов, не могу отделаться от ощущения лёгкого ужаса.
Толсто :-)
В Расте и своих ужасов много. Похоже, подобное заявление имеют право делать только программисты на Си без плюсов :)
Слабоватый список ужасов из пункта про отсутствие стандарта, но и эта тема потихоньку развивается.
Там второй пункт ужасов про библиотеки не раскрыт. А ведь это просто: поскольку нет механизма передачи прав на библиотеку, то если автор её забросил, то усё - пишите форк. Из того, что я видел - это реализация mmap, которая в библиотеке под названием memmap2. ;-)
Вот если сравнить C++ и Rust то есть нотки ужаса. 🥲
Но и попутно мысли есть, что языки созданы для разных целей и у всех есть свой недостатки.
С профилированием, кажется, не все так просто. Время начала захватывается когда, когда лямбда создается? А создается она когда, когда мы pipeline описываем? А запустится он когда, если вообще запустится?
Да, всё именно так, лямбда создаётся в момент выполнения tag_invoke
, то есть при построении sender'а ex::schedule(ps)
, а исполнение лямбды происходит внутри пула, как часть start(os)
-операции, в примере - при вызове sync_wait(pipeline)
. Поэтому корректнее будет сказать, что измеряется задержка между моментом построения sender-а и моментом фактического запуска работы в пуле.
Видимо, слишком размытой получилась формулировка:
<...> выводит задержку переводa задачи в пул <...>, иначе говоря, замеряет время от вызова
schedule(...)
до реального начала выполнения задачи в пуле.
Речь идет о замере времени с момента описания/конструирования, до фактического старта.
Моя личная проблема с чтением всех подобных обзорных статей -- это то, что примеры все какие-то слишком мелкие, тривиальные и, если так можно выразиться, притянутые за уши. Ну т.е. понятно, что что-то сложное вставлять в обзорную статью в стиле "галопом по Европам" нет смысла, т.к. это серьезно "утяжелит" материал. Но, с другой стороны, сложно понять из таких мало кому нужных в реальной жизни примеров в чем же профит.
Интересно было бы посмотреть на использование всей этой кухни в чем-то посерьезнее. Может есть какие-то открытые проекты, в которых подобное уже применяется?
Эти библиотеки были и ранее, если поискать, думаю, можно много найти.
Из того, что выходит по первым кликам: Серверные примеры от NVIDIA, Библиотека Intel для микроконтроллеров, реализующая частичную поддержку P2300, + обсуждения intel о интеграции sender/receiver.
Если наткнетесь на интересные примеры - присылайте, будет, что разобрать
Адаптор
upon_error
позволяет унестиtry/catch
изmain
, сделав логику ошибок отдельной частью кода.
А есть какой-то механизм для работы с опционалами, в частности std::expected? Можно ли иметь несколько блоков обработки типа
...
| ex::then(failiable_1)
| ex::upon_error(on_failiable_1_fail)
| ex::then(failiable_2)
| ex::upon_error(on_failiable_2_fail)
...
Да, можно встроить несколько независимых веток обработки ошибок в один pipeline, как в вашем примере. И да, вы можете адаптировать std::expected
к модели senders/receivers, но для этого потребуется свой адаптер или комбинация существующих (let_value
, just_error
, variant_sender
).
Первый способ - преобразовать expected
в sender, второй способ - танцевать с let_error. Но не факт, что получится без танцев с бубном
Походу многопоточность/параллельность лучше всего писать на verilog.
У типобезопасности и метапрограммных трюков есть некоторая цена, как минимум в эталонной реализации от NVIDIA -- template instantiation stack почти переполняется даже при компиляции hello_world-а. Боюсь себе представить что будет, когда и если этим начнут пользоваться в реальном мире.
Глядя на то что добавляют в новый стандарт, скоро появится встроенный аналог SDL3
А как мне асинхронищину на Boost::ASIO переписать на этот новый "stdexec"? Мне никто не предлагает pool/epoll/uring/.... Наверное, пул-тредов для файловых операций, будет интересно, но сетевые вещи как?
Senders/Receivers в C++26: от теории к практике