
Библиотека cppcoro от Льюиса Бейкера (Lewis Baker) дает нам то, чего не дает нам C++20 — библиотеку абстракций корутин C++, основанную на Coroutines TS.
Пользователь
Библиотека cppcoro от Льюиса Бейкера (Lewis Baker) дает нам то, чего не дает нам C++20 — библиотеку абстракций корутин C++, основанную на Coroutines TS.
Если вы знакомы с курсами Кейт Грегори (Kate Gregory) на Pluralsight, то вас не должно удивить название этой книги. Хотя многие считают C++ сложным языком, код которого зачастую очень трудно читать и поддерживать, он все-таки может быть красивым. Я не совру, если скажу, что со всеми нововведениями язык становится все сложнее. Но в то же время множество новых фич языка и его библиотек направлены сделать современный идиоматический код C++ легче в написании и понимании.
Шесть лет назад, в июне 2016-го года, вышла первая статья об инструменте, с разработкой которого я связан уже много лет. Шестилетней давности публикация дала толчок интереса к SObjectizer-у и, как я понимаю, кто-то сумел попробовать SObjectizer в деле (или собрался попробовать) именно благодаря той статье. Поскольку за прошедшее время SObjectizer несколько изменился, то я подумал, что не помешало бы выпустить обновленную версию статьи. Исправленную и дополненную. С учетом не только того, что в SObjectizer изменилось/появилось/исчезло, но и отталкиваясь от критических отзывов на предыдущие статьи про SObjectizer.
Итак, вашему вниманию предоставляется свежий взгляд на то, что же это за инструмент, для чего он создавался и почему получился именно таким.
Конкурентность сложно как следует наладить, как минимум, тем из нас, кому не повезло писать на языках, непосредственно открывающих нутро конкурентного аппаратного обеспечения: речь о потоках и разделяемой памяти. Не менее сложно организовать конкурентность так, чтобы она работала и правильно, и быстро. Все, что вы знаете об оптимизации однопоточного кода, зачастую вам не поможет. На микроуровне (отдельные инструкции) просто невозможно применить обычные правила, актуальные для μ-операций, цепочек зависимостей, пределов пропускной способности и т.д. При конкурентности правила другие.
Если этот первый абзац вселил в вас надежду, то второй ее обломает: в этой статье я не собираюсь углубленно анализировать самые низкоуровневые аспекты конкурентной производительности. Мы попросту очень многого не знаем о том, как выполняются атомарные инструкции и барьеры памяти, и эту тему мы пока отложим.
Вместо этого я собираюсь дать сравнительно высокоуровневую классификацию, которой пользуюсь для рассуждений о производительности конкурентных операций. Мы сгруппируем вопросы производительности конкурентных операций, выделив шесть обширных уровней, от быстрого к медленному, причем, каждый уровень примерно на порядок отличается по производительности от соседствующих с ним.
Часто ловлю себя на мысли, что рассуждаю именно в таких категориях, когда мне нужна высокопроизводительная конкурентность: каков наилучший уровень, который я реально могу достичь при решении конкретной задачи? Держать в уме эти уровни полезно и на этапе первичного проектирования (иногда небольшое изменение требований или высокоуровневого дизайна позволяют вам выйти на более выгодный уровень), а также при оценке уже существующих систем (для еще более точного понимания имеющейся производительности и выстраивания пути наименьшего сопротивления, ведущего к улучшениям).
Предположим, что в программе на C++ вы возвращаете из функции локальную переменную. Что происходит при вызове оператора return
: копирование, перемещение или ни то, ни другое? От этого зависит длительность вызова функции и эффективность наших программ. Я постарался разобраться с этим вопросом и дам рекомендации по написанию функций так, чтобы повысить шансы на применение этой оптимизации компиляторами. Ну, а сокращения в названии статьи — это Return Value Optimization (RVO) и Named Return Value Optimization (NRVO).
В статье Наблюдение за выполнением конкурирующих задач в Go и Rust коллега cpmonster привёл весьма интересные результаты:
Программа на Rust показала намного большую производительность при вычислении членов возвратной последовательности, чем программа на Go: 367 млн. итераций в секунду против 44 млн.
Ну, в 1.5 раза… Ну, в 2 раза… Но семь гвардейцев за два дня? — это слишком, тем более что тут "гвардейцев" больше восьми!
Или нет, не слишком? В общем, потенциал любопытства пересилил другие потенциалы и я провёл своё исследование.
В C++ есть несколько "умных указателей" - std::unique_ptr
, std::shared_ptr
, std::weak_ptr
. Также есть более нестандартные умные указатели, например в boost: intrusive_ptr
, local_shared_ptr
.
В этой статье мы рассмотрим новый вид умного указателя, который можно назвать static_ptr
. Больше всего он похож на std::unique_ptr
без динамической аллокации памяти.
Контейнер - это объект, используемый для хранения других объектов. Контейнер берет на себя управление всей памятью, которые эти объекты занимают.
В стандартную библиотеку C++ входит несколько контейнеров. Кроме этого, в Open Source есть несколько контейнеров, которые покрывают больше юзкейсов. Я опишу устройство интересных контейнеров вне STL и их отличия от классических контейнеров.
Эта статья представляет собой что-то вроде курсовой работы, которую автор не поленился сделать, изучая одновременно Go и Rust. Сильной стороной обоих языков программирования считается удачно реализованная поддержка конкурентности, во всяком случае, редкий обозреватель обходит эту возможность вниманием. Прочитав несколько довольно подробных теоретических описаний и руководств по разработке приложений с конкурентностью на языках Go и Rust, я решил дополнить их несложным количественным экспериментом и поделиться его результатами.
Все обсуждаемые здесь измерения проведены на единственной системе с более или менее случайными характеристиками. Хотя она довольно типична, то есть, не слишком хороша и не слишком плоха, выполненное в таком объеме исследование заведомо не претендует на полноту. Заинтересованный читатель может повторить его в любой подходящей среде, загрузив исходный код с GitHub (ссылка на репозиторий приведена в конце).
Наконец, не открыв, по-видимому, ничего сенсационного, автор все же надеется, что его статья принесет пользу начинающим разработчикам, а также инженерам и ученым, которые пишут программы для собственных нужд.
Смягчение уязвимости Trojan Source, оптимизация функций приведения типов, многомерный оператор [], подавление предупреждений о вендорных атрибутах — вот лишь некоторые возможности GCC 12. Подробностями делимся к старту курса по разработке на C++.
(на картинке изображён С++ среди других функциональных языков)
Классы - это скорее всего первое, что добавил Страуструп в далёких 1980х, ознаменовав рождение С++. Если представить, что мы археологи древних плюсов, то косвенным подтверждением этого факта для нас будет this, который по прежнему в С++ является указателем, а значит, скорее всего, он был добавлен до "изобретения" ссылок!
Но речь не про это, пора окинуть взглядом пройденный с тех пор путь, изменение и языка и парадигм, естественный отбор лучших практик, внезапные "великие открытия" и понять к чему это всё привело язык, который когда то вполне официально назывался С с классами (ныне мем).
В конце(СПОЙЛЕР) мы попытаемся превратить С++ в функциональный язык за несколько простых действий.
Для начала рассмотрим базовое применение классов:
Любая программа состоит из данных и алгоритмов их обработки. Для написания программ на C++ в начале 90-х годов прошлого века Александр Степанов с коллегами разработал библиотеку STL. Я, Михаил Полукаров из команды разработки VK Teams, заглянул под капот этой библиотеки чтобы разобраться, как правильно ей пользоваться, в каких случаях лучше использовать другие библиотеки, а в каких стоит написать что-то своё.
В первую очередь я поделюсь своим опытом «граблей и багов STL», а также расскажу о почёрпнутом на бескрайних просторах интернета чужом опыте. В перспективе такие знания помогут не только решать поставленные задачи, но и делать это максимально эффективно.
Мудрецы мира С++ часто напоминают нам о том как важно максимально точно выражать свои мысли в коде, делать код понятным и простым, не теряя при этом (а зачастую и выигрывая) в эффективности. Но задумайтесь как выглядит в С++ код связанный с динамическим полиморфизмом.
Встречайте, вот и Go 1.18, а с ней – первый релиз долгожданной реализации дженериков, наконец-то готовых к реальному использованию в продакшене. Дженерики – это весьма востребованная возможность, давно вызывающая жаркие споры в сообществе Go. С одной стороны, самые голосистые беспокоятся по поводу сложности, которую привносят дженерики. Их страшит неизбежная эволюция Go, которая доведет его либо до многословия как в энтерпрайз-версии Java, со своими обобщенными фабриками, либо, самое страшное, превратит Go в вырожденный HaskellScript, где if
-ы придется заменить монадами. Положа руку на сердце, оба этих опасения могут быть преувеличенными. С другой стороны, поборники дженериков считают, что дженерики критически важны для масштабного внедрения чистого кода, пригодного для многоразового использования.
Автор этой статьи не принимает ни одну из сторон в данных дебатах и не дает рекомендаций, где и в каких случаях использовать дженерики в Go. Напротив, эта статья призвана осветить запутанный случай с дженериками в Go с третьей стороны: с точки зрения системных программистов, которые воодушевлены не дженериками как таковыми, а мономорфизацией и тем, как она может сказаться на производительности. Нас таких десятки. Десятки! И мы все имеем изъявить некоторое серьезное разочарование.
Это завершающая часть цикла статей об особенностях так называемых "интеллектуалов" и инструментах, которые помогут нивелировать их нежелательное влияние на жизнь. Весь этот цикл строился не на мемчиках или стереотипах, а являлся осмыслением и обобщением практики моей психологической работы с клиентами.
Традиционный дисклеймер: это не истина в последней инстанции. Это описание методов, которые показали определенную эффективность в определенных вопросах. Не факт, что вам поможет. Как и не факт, что это вам вообще нужно. В общем, не стоит потом меня обвинять, что вы потратили драгоценные минуты жизни на прочтение потенциально бесполезной для вас информации. Я предупредил ;)
Ссылки на предыдущие части, чтобы быть в контексте происходящего:
часть 1
часть 2
часть 3
Окончательно разбираемся с выводами о том, какая криптовалюта наименее подвержена рискам внезапного и резкого обесценения; и в какой крипте риск санкционных заморозок минимален.
Когда вы автоматизируете какую-либо задачу, например, упаковываете свое приложение для Docker, то часто сталкиваетесь с написанием shell-скриптов. У вас может быть bash-скрипт для управления процессом упаковки и другой скрипт в качестве точки входа в контейнер. По мере возрастающей сложности при упаковке меняется и ваш shell-скрипт.
Все работает хорошо.
И вот однажды shell-скрипт совершает что-то совсем неправильное.
Тогда вы осознаете свою ошибку: bash, и вообще shell-скрипты, в основном, по умолчанию не работают. Если с самого начала не проявить особую осторожность, любой shell-скрипт достигнув определенного уровня сложности почти гарантированно будет глючным... а доработка функций корректности будет довольно затруднительна.
Современные тенденции в области аппаратного обеспечения ведут к тому, что использование исключений на C++ всё труднее и труднее оправдать. В представленной работе эта проблема иллюстрируется наглядно, даётся её количественная оценка и обсуждаются потенциальные будущие направления исправления исключений. Материалом делимся к старту курса по разработке на С++.
Программисты читают код намного чаще, чем пишут его, поэтому важно писать понятный, последовательный, однозначный код. Автор книги С++17 in detail написал о способах избегать путаницы. Делимся его материалом к старту курса по разработке на С++.