Pull to refresh
21
0
Алексей @AlexPublic

User

Send message
Если автор «дорос» до такой «инновационной» технологии, как make и при этом параллельно активно использует различные скрипты на Python, то возможно ему стоило бы сделать следующий шаг в развитие и открыть для себя такие слова как Scons, Waf или вообще Bazel. С ними получился бы один простенький и логичный скрипт сборки, а не запутанный монстр, как в статье.
Зачем было использовать ESP32, главной фичей которого является интегрированный wifi (не используемый в данном проекте)? Можно было взять любой приличный МК со встроенным bluetooth (например те же популярные STM32) и избежать половины проблем из статьи.
Никаких особых оптимизаций в C++ мы не делали. Мы согласны с тем, что если покрутить правильные ручки у компилятора, то можно выжать совсем другие цифры.

Делать тесты производительности с C++ без хотя бы опции "-O3" — это уже довольно странная трата времени…

Лично я ожидал, что нативный код будет выполняться значительно быстрее Wasm. Но первые полученные результаты показали, что это не так. И это меня довольно сильно удивило. Планирую вернуться к этому бенчмарку позже.

И правильно что удивило — там точно что-то не так. )

Что касается нашего продукта, то все замеры производительности значат мало что, т.к. на сетевых задержках мы потеряем гораздо больше времени.

Ну я говорил только про обсуждаемый в статье тест — для него очевидно и тесты производительности актуальны и SIMD и т.д. Про продукт в контексте производительности вроде речи не было, так что мои замечания относились не к нему.

Мы честно пытались найти хоть какой-то мало-мальски вычислительный код в продукте. Взяли например обработчик плейлистов. Но на реальных данных код выполняется микросекунды, поэтому бенчмаркать там нечего. К тому же, это совсем не критический участок кода.

Если у вас там видео воспроизводится, то можно посмотреть различные латентности, особенно в 4K и со сложными кодеками. )
Гарантий нет, но ведь всегда есть достаточно безопасные и предсказуемые кусочки программы, про которые что-то можно доказать.

Проблема в том, что на уровне машинных кодов невозможно получить гарантии. Потому как JIT компилятору неоткуда знать, что к данной ячейки памяти нет доступа у какого-то другого кода. Т.е. тот же C++ компилятор ещё может делать подобные выводы например по отсутствию ссылок (или операций взятия адреса) на данную переменную. А при просто потоке машинных кодов, обращающихся к каким-то произвольным участкам памяти, как гарантированно понять, что какой-то посторонний код (в худшем случае вообще в параллельном потоке — этого сейчас в WASM нет, но планируется в ближайшее время) не поправит данную ячейку памяти (которая потом используется как указатель)?

А браузеру вовсе не нужно с данной памятью работать. Учитывая, что в WebAssembly пока размер кучи ограничен 2^32, а процессоры у нас 64-битные, можно тупо нарезервировать страниц как раз на 2^32, но на реальные физические отобразить ровно столько, сколько заявлено в дескрипторе wasm-модуля (ну и по мере вызова grow_memory отображать дополнительные).

Ээээ что? Что значит браузеру не нужно с данной памятью работать? Ему не нужна вообще никакая память для своей личной работы или как? А если хоть какая-то нужна, то как её защитить от доступа из WASM модуля с помощью защиты страниц виртуальной памяти?

Вы хотите сказать, что clang берёт и сам генерит векторные инструкции? Мне казалось, что они всё-таки получаются в процессе работы самого LLVM. Учитывая, что с точки зрения меня, как разработчика приложений, формат wasm является всего лишь форматом обмена данными, мне всё равно, в какой там IR браузер разворачивает мой wasm-модуль и как его оптимизировать.

Ни в какой IR модули WASM в браузере не разворачивается. Формат wasm — это по сути и есть IR, представляющее собой ассемблерные инструкции некого виртуального процессора. Причём этот формат является чуть изменённой (упрощённой и с большей безопасностью) версией IR из LLVM. К сожалению векторные типы LLVM не вошли в первую версию WASM.

Или разработчики WebAssembly не хотят, чтобы браузер делал векторизацию и хотят переложить эту заботу на компилятор? Ну тогда я всё равно не вижу практической невозможности позволить генерацию быстрого кода, я вижу только невозможность сочетать это с быстрым запуском кода.

Не нехотят, а это единственное разумное решение. И собственно говоря уже все материалы (типы, инструкции) для реализации подготовлены: github.com/WebAssembly/simd/blob/master/proposals/simd/SIMD.md. Но в текущий «стандарт» WASM это пока не входит.
Вот уж не знаю как. Я точно помню, как общался с сотрудниками Мозиллы и они мне говорили про багу в range analysis ещё в альфа-версии WebAssembly. Как минимум, нижняя граница определена в compile-time (в WebAssembly-модуле для heap необходимо указывать минимальный и максимальный размер хипа), а то, что указатель известен только в рантайме, ещё не значит, что его диапазон нельзя оценить с помощью статического анализа. Такое, например, реализовано в JVM для устранения проверки на выход за границу массива.

Так нужны гарантии, что эти значения не меняются. Именно в этом проблема, а не в определение самих значений. Собственно единственная оптимизация, которую реально делают все подобные инструменты, это убирание повторных проверок (ну типа если мы дважды обращаемся по одному указателю внутри одной итерации цикла).

mprotect в POSIX. В Windows тоже был системный вызов, но я с ходу не вспомнил название.

VirtualProtect это в Винде. Только ничем эти функции не помогут для решения данной проблемы. Если закрыть с помощью них доступ к какой-то области памяти, то каким образом сам браузер будет работать с этой областью памяти?

Там есть всё необходимое. Вот как-то C-компиляторы делают это. А они, заметьте, никогда не оптимизируют непосредственно AST C. Т.е. они строят IR (промежуточное представление), которое как раз очень похоже на портабельный ассемблер, а потом уже находят в нём циклы, которые можно векторизовать. Для этого есть куча способов, есть много специализорованной литературы, которая рассказывает про это (вот даже последние редакции Dragon Book рассказывают про векторизацию), и есть ещё большая куча всяческих статей от авторов тех или иных компиляторов.

С учётом того, что в LLVM IR имеются векторные типы, это конечно очень большая загадка, как это делается. ))) Кстати, ещё забавный вопрос: интересно, как укладывается в это ваше видение факт работы OpenMP SIMD (у уже молчу про intrinsics)?

Полагаю, что статья автора как раз не про драйвера и ядра ОС.

Речь о том, что отказ от исключений уж точно не ведёт к потере производительности. )
Само собой. Например, хотя у нас в имеются специалисты с экспертным знанием C++, но для бэкенда наших сайтов используется вообще дико медленный Питон, потому как C++ нам тут просто не нужен — мы не Гугл или Яндекс. Однако все эти размышления не имеют никакого отношения к моему изначальному замечанию — там речь шла совсем о другом:

если у ребят получилась одинаковая производительность подобного алгоритма на JS, WASM (C++) и нативном C++, то практически гарантированно у них что-то очень не так в варианте нативного C++.
Мне кажется, что проверка на выход за границы heap-а в ряде случаев может убираться оптимизатором.

Каким это образом, если и значение указателя и значения границ определены только в рантайме?

Кроме того, часть работы по отлову выходов за границу хипа можно сделать через защиту памяти.

Каким образом можно в рамках одного процесса закрыть некому коду доступ к какой-то области выделенной памяти?

Что касается SIMD, опять же, браузер может сам анализировать WASM и автоматом векторизовать его (для этого в WASM есть всё необходимое).

Нет там ничего необходимого. В будущем появится (соответствующие инструкции), но пока нет.

А если бы можно было делать автовекторизацию напрямую из машинных кодов, то такой алгоритм давным давно внедрили бы непосредственно в конвейер CPU.

По крайней мере, LLVM ровно так и делает.

Ээээ что? Где это он так делает?

Нет возможности получить указатель на переменную в стеке. Если такой указатель где-то берётся, то приходится размещать переменную в shadow-стеке, со всеми накладными расходами на поддержание shadow-стека.

Хм, да это интересный момент. Я его не смотрел. Причём с учётом того, что итоговая машина всё же стековая, у WASM JIT'a в теории есть большое поле для оптимизации. А вот делается ли там сейчас что-то для этого или нет — не знаю. Хотя это не сложно посмотреть, т.к. исходники открыты.

Нет возможности вообще как-то погулять по стеку, чтобы, например, сгенерировать исключение. Да и нативную поддержку исключений пока не завезли. Так что единственная возможность — это вставлять всюду проверки.

С учётом того, что в наиболее требовательных к ресурсам приложениях (программирование различных МК, ядра ОС, дравейров и т.п.) как раз применяется режим C++ с отключёнными исключениями, то данная особенность если и влияет на производительность, то только положительно. )))
Все приложения разные, а JIT в браузерах творит чудеса.

Нет там никаких чудес. Каждый раз, когда я видел утверждения о равенстве быстродействия с C++, всё сводилось к кривому использованию последнего (собственно иначе и быть не может, т.к. тогда бы уже давно писали бы браузеры на js). Для схожего с использованным в статье для тестов алгоритмом у меня были следующие результаты (это усреднённое время в мс):

JS 15,6
C# 15,1
ASM.JS (из C++) 12,5
WASM из ASM.JS 11,4
Java 10,1
C# unsafe 8,9
WASM 8,6
D 7,2
C++ nosimd 4,4
C++ 1,5
Хорошая статья по WebAssembly. Единственное, чтобы я добавил, это что для сборки C++ кода в WASM не требуется обязательно Emscripten. Для собственно компиляции достаточно просто компилятора LLVM (естественно собранным с поддержкой WASM и Clang'ом). И именно его использует Emscripten внутри себя. А смысл проекта Emscripten не в генерации WASM (или даже asm.js, с чего всё начиналось), а в генерации JS обёрток, реализующих функциональность стандартных библиотек C++ через браузерное API. Т.е. без Emscripten (с чистым LLVM) не будет возможности даже для вызова функции типа printf (но при этом будет базовая возможность вызвать произвольную JS функцию из страницы, в которую загружен wasm модуль).

Да, ну и вот эта цитата:
Но когда включается оптимизация (зеленый столбик), мы получаем время, практически совпадающее с JS. И, забегая вперед, мы получаем аналогичные результаты в нативном коде, если скомпилируем С++, как нативное приложение.

означает, что у вас есть какие-то фундаментальные проблемы в вашем нативном C++ приложение. Т.е. мои тесты вполне подтверждают ваш результат, что WASM в данное время сравним по производительности с JS. Но при этом тот же C++ код скомпилированный в машинные коды всегда получается в разы быстрее. И на это есть две фундаментальные причины:
1. WASM с одной стороны предоставляет полный доступ к работе с указателями, а с другой должен гарантировать безопасное выполнение подобного кода внутри песочницы (у модуля не должно быть способа залезть в данные браузера или других модулей). Как следствие этого, IR код работы с памятью компилируется (при загрузке модуля в браузере) не в прямую инструкцию x86, а с дополнительной проверкой выхода за границы выделенной памяти. На активно работающем с памятью коде, это может давать просадку производительности х2 раза.
2. SIMD. В будущем в WASМ планируют завести поддержку SIMD инструкций, но пока этого нет. В JS этого нет тем более. А в любом приличном компиляторе C++ уже много лет как поддерживается автовекторизация циклов, которая может давать увеличение быстродействие вплоть до х7 раз (для самых подходящих циклов, но в коде графических фильтров изображений должно быть полно таких).

В общем не знаю где у вас там конкретные косяки с C++, но если у вас скомпилированное в машинные коды приложение исполняется столько же, сколько WASM и JS варианты, то эти косяки у вас однозначно есть.
Да, я вспомнил что в десятки раз — это касалось не openocd, а родной утилиты от STМ (называется ST-LINK Utility), которой я пользовался для прошивки до j-link.
Насколько софт JLink быстрее? Полагаю, что главным фактором, определяющим время прошивки, является всё же скорость соединения дебагера.

В десятки раз. На том же железе (но с другой прошивкой программатора).

Qt Creator поддерживает только openocd и st-util

Это не так. Qt Creator изначально поддерживает ровно один универсальный режим отладки — удалённый gdb. Плюс к этому там есть две дополнительные предустановки для st-link и openocd. Однако это всего лишь для удобства — можно без проблем настроить тот же openocd (который естественно реализуют gdb сервер) через общий универсальный режим (он в настройках Qt Creator называется «по умолчанию»).

Так что отладка через j-link (ПО, а в качестве железа служит обычный st-link, перепрошитый под j-link их официальной утилитой) у меня отлично работает из Qt Creator.

работа под линуксом — это два (хотя мб софт jlink тут тоже работает)

Есть и под винду и под линух и под мак.

openocd это универсальный комбайн, поддерживающий хоть stm32, stm8, отечественные кортексы — это три

Так j-link аналогично. И более того, там получается одно универсальное решение не только со стороны ПО, но и одно аппаратное решение для всех МК.

целый зоопарк отладчиков помимо jlink и stlink — это четыре

В данном сравнение это получается уже скорее минус, чем плюс. )))

ну и возможность лазить в сходники и делать любые фиксы — это пять.

А вот это да, я бы тоже предпочёл иметь открытые исходники ПО от Segger. Но боюсь в таком случае у них не вышло бы нормально зарабатывать… ))) Так что уж лучше качественное закрытoe ПО.
Из всего семейства Сortex-M вывода SWO нет лишь у M0/M0+ — поэтому решение прокатывает в большинстве случаев.

Ну вот например у нас из МК используются исключительно STM32F0, так что для нас это «лишь» является наоборот «всем». )))

Раньше вот даже не знал, что RTT уже c openocd скрестили, а теперь руки чешутся всё это дело проверить.

А зачем обязательно openocd использовать? Почему не попробовать более мощный j-link? Оно же даже без логирования и отладки намного удобнее, например хотя бы временем прошивки…
Semihosting — довольно медленный, RTT — завязан на программно-аппаратные решения Segger, USB — есть не в каждом микроконтроллере. Поэтому обычно, я отдаю предпочтение последним двум — использование UART и ITM.

SWO к сожалению тоже есть далеко не в каждом STM32. Ну а использование UART — это уже нагрузка на МК и использование периферии, т.е. уже не похоже на нормальный режим отладки. Так что на мой взгляд единственным универсальным и при этом эффективным способом логирования является технология типа Segger (там же на самом деле нет ничего такого секретного и проприетарного — просто периодическое чтения блока памяти через отладчик, можно самому легко написать, если есть желание).

Ну и кстати говоря, если уж говорить про непосредственно Segger, то их ПО (j-link, которое на мой взгляд на голову лучше openocd) спокойно работает с обычными st-link. Так что никакой привязки к их недешёвому железу нет.
Вы много сами-то в Китае производили и закупали?..

Ничего не производил, но много закупал.

А то у нас там, например, свой человек есть, и он настоятельно не рекомендует в принципе

Ну т.е. опыта закупок компонент в Китае у вас нет, правильно?

делать там партии размером меньше одной катушки — ни с точки зрения качества компонентов, ни с точки зрения качества монтажа (и да, в пробной партии в сотню штук изделий с компонентами 0201, сделанной в Китае, брака была половина, то же устройство, те же 100 штук, сделанные на метро Савёловская — 96 из 100 полностью исправны).

Ээээ что? Какое вообще отношение имеет заказ сборки плат в Китае к обсуждаемой теме (мелкосерийного производства плат в России)?

Каких «надёжных поставщиков» вы там собрались искать без своего человека на месте и при закупках под опытные партии — для меня загадка. С большой вероятностью ваш «надёжный поставщик» будет полуподвальной конторой в три человека (из которых английский знает одна девочка, и нет, Angel — не её настоящее имя, для европейцев у них псевдонимы), сгребающих ваш заказ с ближайшего рынка.

О, я смотрю очередное сильно аргументированное утверждение… )))

Какое отношение механическая загрузка компонент имеет к программированию?

Как только предложите, как без неё обойтись — сразу же все дружно решим, что никакого.

Ну так и без закупки и доставки компонент у поставщика тоже невозможно обойтись! Так что, включаем время на доставку в «программирование станка»?
Потому как со временем появится список надёжных поставщиков для каждого вида компонент

При нерегулярной покупке менее 10 тыс. компонентов? Не появится.

Сильное утверждение. ))) А как насчёт такой же сильной его аргументации?

Я прямо вижу, как вы за пару минут проходитесь по десятку-двум-трём лент с лупой, выписываете ориентацию компонентов в каждой из них и одним движением вписываете коррекцию угла поворота относительно экспортированного из CAD по лежащему там футпринту.

Это всё делается не при каждом изготовление платы, а при поступление заказанного компонента на склад. Причём делается даже в том случае, если в ближайшее время не намечено использование этого компонента — как раз чтобы потом, в самый нужный момент, не потребовалось измерять десятки компонент сразу. Хотя вообще говоря это простейшее дело (внести пару измерений в табличку в excel'е), но удобнее, когда этим занимается соответствующий человек в оптимальное время, а не разработчик в процессе изготовления прототипа платки.

Потом ещё секунд за тридцать ставите на станок два десятка катушек, десяток отрезков и пару поддонов.

А причём тут это вообще? Напомню, что в статье была фраза: "программирование расстановщика у вас займёт сильно больше времени, чем собственно расстановка". Какое отношение механическая загрузка компонент имеет к программированию? Или может тогда ещё доставку компонент от поставщика включим во время программирования? )))

Ну и за оставшиеся пять секунд проверяете, что он увидел и скорректировался по реперным точкам.

Вот собственно это и есть единственное действие (помимо загрузки файла, выданного CAD'ом) в управляющем ПО станка, которое действительно необходимо сделать. И да, оно занимает как раз несколько секунд.

Что для всех компонентов правильно указано место подачи. Что нижняя камера не ошибается ни на одном из компонентов, что верхняя камера правильно различает чёрные компоненты на чёрном фоне в поддонах…

Про компоненты уже написано выше.
Вы видимо никогда не работали с автоматическими установщиками компонентов. В теории, все просто — импортировал PnP файл из CAD-а и готово. На самом деле, это только 1% от всей работы по настройке (или как говорят — программированию) установщика и подготовке к запуску производства. Требуется как минимум разместить компоненты в машине (решить логичстическую задачу, зарядить катушки или заправить обрезки лент), прописать и проверить все координаты и высоты подбора, создать образы, проверить их и убедиться что машина распознает все компоненты с вероятностью более 95%. После чего нужно описать плату, описать реперные метки, проверить их распознавание. Под конец пройтись по placement файлу и убедиться, что все компоненты стоят на своих местах, а не со смещением, что повернуты они верно, катоды/аноды у диодов расположены верно и т.д. Вобщем, коллега olartamonov совершенно прав, иногда подумаешь стоит ли включать машину, или может паяльник в руки, пару часов и готово :-).


Всё очень правильно описано. Если только не считать скромного умолчания того факта, что все приведённые выше действия производятся один раз на установку станка или один раз на закупку нового компонента, но уж точно не один раз на каждую плату. А этот нюанс меняет всё, потому как если мы имеем уже распакованный станок и подготовленный склад компонентов, то подготовка расстановки компонент для новой платы действительно занимает пару кликов мышкой.
Рано или поздно вы купите катушку-другую откровенного брака или и вовсе перемаркированных изделий.

Как раз наоборот. Чем больше покупаешь, тем меньше шанс получить такое. Потому как со временем появится список надёжных поставщиков для каждого вида компонент. Это скорее при первой закупке в Китае есть небольшой шанс нарваться на жуликов, а потом просто ходишь по знакомым и всё.

Нет, они этого не делают.

Всегда любил читать на форумах утверждение народа, опровергающие объективную реальность у меня под боком. И главное эти утверждение иногда делают так уверенно, что прямо начинаешь сомневаться — может это у меня галлюцинации были или ещё что? )))

Вот прямо сейчас нажал на одну кнопочку в CAD'е и получил файл позиций (внутри просто csv файл). Нажал вторую и получил его адаптацию (по факту добавление пары колонок и иногда изменение одной существующей) под конкретный набор компонентов, установленных на станок (опции компонентов хранятся в в отдельном csv файле и правятся при поступление компонент на «склад»).

Да, и кстати второй шаг можно было не делать, т.к. ПО управления станками достаточно передать только первый файл (просто позиции), но тогда бы пришлось указывать эти значения в самом интерфейсе этого ПО (в принципе тоже за пару минут делается, т.к. можно выделять однотипные компоненты вместе, но зачем делать руками то, что может сделать компьютер?).
Несколько комментариев:

По закупке. Насчёт Китая зря так кратко сказано. Для цифровой электроники обычно не так принципиальна точность параметров компонентов (а для всяких там микроконтроллеров вообще нет разницы). Так что при правильной системе налогообложения (не говоря уже о физических лицах) закупка в Китае может быть ультимативным решением.

Про печатные платы. В целом согласен. Но недавно увидел вот такую wegstr.com штуку и думаю её прикупить для прототипов (ну и соответственно для совсем мелких партий может пойти), причём там у них сразу и решение для маски и для переходных отверстий. За одно это же устройство может и трафареты (причём металлические) делать.

Про нанесение пасты. Согласен что есть два современных метода, но один из них не тот, что у автора. Выбор должен быть между: нанесением через трафарет и автоматическим дозатором (бывает совмещённым с расстановщиком). А ручной дозатор — это решение не сильно лучше паяльника.

Про расстановку компонент. Вот автор частенько упоминает, что надо жить решениями 21-го века, а при этом сам допускает высказывания актуальные десятилетия назад. Типа такого: «скажу вам по секрету, на партии в полсотни плат программирование расстановщика у вас займёт сильно больше времени, чем собственно расстановка.» Вообще то современные CAD'ы уже давно делают это автоматически (т.е. цена вопроса в пару кликов мышки). Так что единственным минусом решения с автоматическим расстановщиком является его цена. Которая пока ещё достаточно неадекватна для производства одиночной платы любителем. Однако уже даже для мелкосерийного производства это становится ультимативным решением (правда пока ещё только китайские варианты).

Можно решать задачу через акторов, можно через сопрограммы, можно через сигналы, можно «лапшой», можно через visitor, можно через монады… Что выбрать — зависит от множества факторов.

Полностью согласен. Более того, я об этом писал выше, а реализация через модель акторов являлась лишь одним из примеров, выбранным потому, что изначальный вариант кода уже был очень похож на них.

В статье про сопрограммы даётся пример, что можно решать через сопрограммы.

А вот здесь не согласен. Потому как без проблем можно забивать гвозди с помощью тяжёлого гаечного ключа, одна вряд ли описание подобного процесса будет идеальным гайдом по использованию гаечных ключей…

Если вы так уверены в безоговорочной победе акторов, давайте всё же сравним полные реализации. Напишите пожалуйста полный рабочий пример с акторами, за основу возьмите код из статьи

Ну вообще то, как я уже говорил, код выше — это практически всё что надо. Ему осталось добавить только конструкторы, main и include'ы. Однако если так уж хочется взглянуть на полный компилируемый пример, то накидаю на днях.
На мой вкус — не лучше лапши.

Ну как же. Тут у нас:
1. Принципиальное отсутствие лапши — добавление функции любой сложности не добавляет ни одного уровня вложенности.
2. Нормальная модульность, которая не просто удобна для разделения работы между разными специалистами, но и позволяет безболезненно менять приложение. К примеру в моём коде я могу без каких-либо сложностей сменить весь UI код (скажем решив поменять используемую GUI библиотеку), в то время как сделать аналогичное, при размазанном по всему проекту UI коду, практически не реально.
3. И данный пример может даже легко поддержать старый интерфейс (для любителей лапши) — достаточно добавить в акторы ещё один обработчик сообщений, принимающий и исполняющий лямбды.

При программировании на ASIO всегда раньше были упрёки «У нас 1 действие разваливается на кучу мелких шагов, разбросанных по исходникам. Не видна последовательность шагов при беглом взгляде». Почему при прграммировании с акторами это считается плюсом — мне не ведомо.

Не стоит смешивать пример из статьи и ASIO, т.к. есть как минимум пара принципиальных различий:
1. Асинхронный код при реализации сервера (работающего со многими клиентами) является необходимость из соображений производительности. В то время как для примера выше он не просто ненужен, а даже менее эффективен (в ситуации когда число одновременных задач сравнимо с числом ядер процессора).
2. В ASIO разбивается на кусочки (и склеивается с помощью сопрограмм) конвейер обработки сетевого запроса. Это не имеет ничего общего с примером выше, в котором смешиваются сетевые запросы, работа с UI и ещё чёрт знает что.

Поставьте ваш пример рядом с финальным результатом с сопрограмами и сравните, что лучше.

Ха, так даже сравнивать нечего. Мой пример — это практически законченный код, в который осталось добавить конструкторы акторов (в которых задаётся соответствие между типом обрабатываемого сообщения и конкретной функцией-обработчиком) и можно компилировать и использовать. А для аналогичной ситуации с кодом на сопрограммах, к нему надо ещё добавить:
— код CoroTask
— код PromiseType
— код WorkQueue.

В итоге мой пример будет выглядеть в разы лаконичнее. )))

P.S. Самое забавное, что изначальный пример статьи по своей сути является реализацией модели акторов, только сильно упрощённой, со всего одним типом сообщений (std::function). Стоит убрать это упрощение и понять, что можно передавать сообщения разных типов, как сразу пропадает необходимость в лямбдах (и соответственно порождаемая их вложенностью лапша).
1
23 ...

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity