Как стать автором
Обновить

Senders/Receivers в C++26: от теории к практике

Уровень сложностиСредний
Время на прочтение15 мин
Количество просмотров4.6K
Всего голосов 24: ↑24 и ↓0+31
Комментарии22

Комментарии 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. Но не факт, что получится без танцев с бубном

У типобезопасности и метапрограммных трюков есть некоторая цена, как минимум в эталонной реализации от NVIDIA -- template instantiation stack почти переполняется даже при компиляции hello_world-а. Боюсь себе представить что будет, когда и если этим начнут пользоваться в реальном мире.

Глядя на то что добавляют в новый стандарт, скоро появится встроенный аналог SDL3

А как мне асинхронищину на Boost::ASIO переписать на этот новый "stdexec"? Мне никто не предлагает pool/epoll/uring/.... Наверное, пул-тредов для файловых операций, будет интересно, но сетевые вещи как?

А её точно нужно переписывать на это? Вроде же совершенно разный уровень...

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации