Обновить
256K+

C++ *

Типизированный язык программирования

456,38
Рейтинг
Сначала показывать
Порог рейтинга
Уровень сложности

Введение в высокопроизводительные вычисления на С++ для CPU

Уровень сложностиСредний
Время на прочтение15 мин
Охват и читатели17K

"Поскольку вы программист на C++, вероятность того, что вы слегка одержимы производительностью, выше среднего. А если нет, то вы, вероятно, по крайней мере с пониманием относитесь к такой точке зрения. (Если производительность вас совсем не интересует, аудитория Python разработчиков дальше по коридору)"
— Из пункта 42 книги С. Майерса “Effective Modern C++”, 2015.

Эта заметка описывает мой личный взгляд на то, как писать эффективный и надежный код для CPU. Статья ориентируется на С++, но значительная часть обсуждения CPU, кэшей, паттернов доступа к памяти и профилирования применима к Rust, Go и другим компилируемым языкам. Статья задумана как краткое введение и больше всего подходит студентам, имеющим опыт программирования на занятиях, но не в реальных проектах. Для профессионалов статья может быть полезной в качестве референса, чтобы не пугать новичков чем-то в духе Что каждый программист должен знать о памяти.

В статье опишу "набор новичка": godbolt.org, профилирование, бенчмарки, особенности CPU и его взаимодействия с памятью, когда есть смысл от асимптотических оптимизаций и почему важно при этом пользоваться санитайзерами, отслеживать coverage и вообще более трепетно относится к надёжности.

Читать далее

Что больнее OT или CRDT в совместном редактировании? И почему до сих пор нет идеала?

Уровень сложностиСредний
Время на прочтение26 мин
Охват и читатели10K

Привет, Хабр!

Меня зовут Антон Леонтьев, я старший разработчик в команде ядра редакторов МойОфис. Мы создаём офисные приложения, которыми ежедневно пользуются более 12 500 организаций, и совместное редактирование — одна из ключевых возможностей наших продуктов.

И знаете, что самое обидное в этой теме? За 35 лет исследований были опубликованы сотни научных работ. Google Docs работает с 2006 года. У Figma, Notion и Linear свои реализации. Казалось бы, задача давно решена, но стоит копнуть глубже, и становится понятно: универсального решения нет.

В Google Drive и Dropbox до сих пор всплывают баги с одновременным перемещением папок. В Notion при параллельном редактировании одного и того же абзаца можно потерять часть изменений. Даже Yjs — самая популярная CRDT-библиотека — не хранит полную историю документа в привычном для нас виде.

В этой статье разберём теорию, узнаем, какие проблемы решают Operational Transformation (OT) и Conflict-free Replicated Data Types (CRDT), на каких математических идеях они основаны, чем отличаются архитектурно и какие компромиссы неизбежно возникают в каждом подходе.

Интересно узнать, почему даже Google не смог сделать идеальное решение? Детали под катом.

Читать далее

Безумие препроцессора: внедряем do-нотацию для монад из Haskell в C++

Уровень сложностиСложный
Время на прочтение12 мин
Охват и читатели9.3K

Добро пожаловать в чистилище препроцессора — место, где здравый смысл уступает место макросам. Сегодня мы заставим C++ притвориться Haskell-ем и внедрим do-нотацию, за которую любой адепт «чистого языка» предаст нас анафеме.

Программисты на C++ делятся на два типа: те, кто боится препроцессора, и те, кто познал сие древнее чудо с сишных времён.

Сегодня мы перейдем черту. Функциональное программирование манит своими абстракциями, но когда дело доходит до цепочек вычислений в монадах, C++ встречает нас бесконечными лямбдами и вложенностью, от которой рябит в глазах. В Haskell эта проблема решена элегантным do-синтаксисом. А что, если я скажу, что мы можем получить то же самое в C++, используя лишь тёмную магию макросов, простые шаблоны и полное пренебрежение здравым смыслом?

Приготовьтесь: мы будем дорабатывать парсер и превращать ваш код в нечто, что заставит коллег вызвать экзорциста. Это история о том, как затащить чистую красоту монад в суровый мир C++.

Запустить конвейер безумия

Jami в России: почему гениальный P2P-мессенджер не работает и как это исправить

Уровень сложностиПростой
Время на прочтение11 мин
Охват и читатели14K

Я не участвую в разработке Jami и не являюсь профессиональным разработчиком этого проекта. Однако я потратил достаточно времени, изучая архитектуру Jami, тестируя его в российских сетях и разбираясь в документации.

В процессе стало очевидно две вещи:

· У Jami огромный технический потенциал.
· В реальных сетевых условиях (особенно в мобильных сетях России) он работает значительно хуже, чем мог бы.

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

Если вы разработчик, знакомый с C++, сетевыми протоколами, ICE или распределёнными системами — возможно, этот разбор будет вам интересен.

Читать далее

Создание библиотеки на C++. Часть III

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели5.4K

Привет! Меня зовут Николай, я C++-разработчик в SimbirSoft. Это третья часть цикла статей о проектировании библиотек на примере решения геометрических задач.

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

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

Также рассмотрим практические примеры: адаптацию стандартных контейнеров, расширение алгоритмов через частичную специализацию и добавление альтернативных реализаций. В завершение покажем, как возможности стандарта C++20 позволяют упростить архитектуру за счёт использования концептов и отказаться от части вспомогательных сущностей.

Для комфортного чтения потребуется уверенное понимание шаблонов, частичной специализации и базовых принципов обобщённого программирования в C++. Материал ориентирован на разработчиков уровня middle и выше, которые интересуются проектированием расширяемых библиотек и архитектурой современных C++-систем.

Читать далее

Raspberry Pi 5 – CEF или WebKit для off-screen рендера?

Уровень сложностиСложный
Время на прочтение9 мин
Охват и читатели6.4K

Цель статьи – объяснить разницу между CEF и WPE после года работы с этими фреймворками, предоставить инструкцию сборки и запуска полноценных JS+HTML+CSS веб-страниц с WPE на RaspberryPi 5 с zero-copy в 60+ FPS на FullHD. Посетовать, что такое нельзя сделать вместе с CEF. В конце мы будем иметь:
WPE для arm64 и amd64, OpenGL пайплайн вместе с EGL, работать всё это будет на встроенной системе Wayland. Wayland не должен никого пугать, на RaspberryPi 5 он идёт сразу в коробке, так что вы можете запускать и приложения на Wayland, и без перезагрузки приложения на X11. Но WPE zero-copy работает ТОЛЬКО с Wayland. Код будет представлен на языке С++.

Читать далее

А давайте переложим данные из unordered_map в unordered_map

Уровень сложностиСредний
Время на прочтение4 мин
Охват и читатели8K

Задался вопросом - как связаны порядки (в смысле перебора от begin к end) элементов в хеш-таблице, если её сначала сериализовать, а потом результат распарсить. Друими словами - смотрим на преобразование

T RefillSimple(T& x) { T res; for(auto& p : x) {res[p.first] = p.second;}; return res; }

Вариант перекладывания, сохраняющий порядок, получить удалось - и для меня это стало неожиданностью.

п.с.
(сори за форматирование - предпросмотр для ленты не сохраняет переносы в коде )

Читать далее

ProcessEvent на стероидах: сериализуемые вызовы функций в UE5 или как я готовлю материал для статей

Время на прочтение7 мин
Охват и читатели6K

В предыдущих двух статьях я разбирал K2Node - как устроены ноды Blueprint изнутри - и Blueprint VM: байткод, опкоды, стековую машину. Следующая на очереди - Reflection: UClass, UFunction, FProperty и вся система метаданных, на которой стоит движок.

Готовясь к ней, я решил, что лучше всего разобраться в теме поможет практика. И тут подвернулся юзкейс: мне нужен был способ сконфигурировать вызов произвольной функции в редакторе и выполнить его в рантайме. Без хардкода, без кодогенерации, без десятка одинаковых обёрток. Так появился FunctionHandler - плагин для UE 5.6, в котором пригодилось всё, о чём я писал раньше: CustomThunk'и, ExpandNode, работа с FFrame и MostRecentProperty.

Эта статья - про то, как всё сошлось в одном плагине, какие решения сработали, и на какие грабли я наступал.

Читать далее

Как мы подружили однопоточный C++ с многопоточным Rust

Время на прочтение23 мин
Охват и читатели12K

Этот пост написан по мотивам выступления, с которым мы с Шисянь Ван ездили на конференцию Rust UnConf, организованную нью-йоркским сообществом Rust. Конференция UnConf собрала поистине потрясающий коллектив энтузиастов a Rust, в компании которых мы более двух часов посвятили глубоким техническим дискуссиям (а также поеданию мороженого). Далее при необходимости я буду ссылаться на опыт нашей компании Antithesis.

Читать далее

От MNIST к Transformer. Часть 3. Умножение тензоров. Пишем Linear Layer

Уровень сложностиСредний
Время на прочтение14 мин
Охват и читатели7K

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

Это третья статья из цикла От MNIST к Transformer, цель которого пошагово пройти путь от простого CUDA ядра до создания архитектуры Transformer - фундамента современных LLM моделей. Мы не будем использовать готовые высокоуровневые библиотеки. Мы будем разбирать, как все устроено под капотом, и пересобирать их ключевые механизмы своими руками на самом низком уровне. Только так можно по настоящему понять как работают LLM и что за этим стоит. В этой статье мы перейдем от матриц к такому понятию как тензоры, напишем умножение тензоров, так же создадим свой первый линейный слой или полно-связную нейронную сеть. И наконец напишем сеть для распознования mnist датасета.

Приготовьтесь, будет много кода на C++ и CUDA, работы с памятью и погружения в архитектуру GPU. И конечно же математика что за этим стоит. Поехали!

Читать далее

Работаем с контейнерами в C++ с помощью библиотеки Ranges

Уровень сложностиСредний
Время на прочтение7 мин
Охват и читатели7.4K

Понятие контейнер сейчас активно применяется в контексте Docker и аналогичных решений по контейнеризации. Однако, в языке C++ контейнеры существуют уже очень давно и являются фундаментальной частью Standard Template Library (STL). Они предоставляют готовые реализации наиболее часто используемых структур данных, избавляя разработчика от необходимости писать их с нуля.

Контейнеры C++ можно разделить на несколько основных категорий. Последовательные контейнеры (Sequence Containers) хранят элементы в линейной последовательности, при этом порядок элементов определяется позицией добавления. Ассоциативные контейнеры (Associative Containers) автоматически сортируют элементы по ключу. При этом, они обеспечивают достаточно быстрый поиск (O(log n)). Неупорядоченные ассоциативные контейнеры (Unordered Associative Containers) хранят элементы в хеш-таблицах. Обеспечивают поиск в среднем за O(1). Адаптеры контейнеров (Container Adapters) предоставляют ограниченный интерфейс поверх других контейнеров.

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

Читать далее

Черная магия unsafe в Go: практические примеры и ошибки использования. Часть 1

Время на прочтение13 мин
Охват и читатели6.2K

В стандартной библиотеке Go есть пакет с отпугивающим названием «unsafe». Но он может быть реально полезен! Сегодня поговорим о том, как использовать его надежно и эффективно.

Привет, Хабр! Я — Владимир Балун, основатель balun.courses и it-interview.io. Эта статья будет для удобства разделена на две части. Из них вы узнаете, как можно создавать срезы без дорогостоящей инициализации, научитесь избавляться от Bound Checks и конвертировать строки в срезы и обратно без лишних копирований и аллокаций памяти. 

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

Читать далее

Мой плохой код — это ваша вина

Уровень сложностиСложный
Время на прочтение14 мин
Охват и читатели30K

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

Я как-то привык что если что-то ломается или плохо работает, то это я виноват. Это называется «брать ответственность за свои поступки» или, в случае программиста, за свой код, и это считается хорошим делом.

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

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

Сейчас я вам это покажу. Будет интересно, но впереди много боли. Я предупредил.

Хочу страдать

Ближайшие события

Почему у нас нет кешей L5?

Уровень сложностиПростой
Время на прочтение13 мин
Охват и читатели28K

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

Первое, что нужно понять: процессор не является абстрактным вычислителем, а вполне себе реальный кусок кремния размером примерно с ноготь большого пальца, на котором размещены миллиарды транзисторов и когда мы говорим «данные передаются из памяти в регистр», то мы буквально имеем в виду, что электрический сигнал проходит по металлическому проводнику длиной в несколько миллиметров или сантиметров. И это тоже расстояние, пусть и ничтожное по человеческим меркам, но при тактовой частоте 3–4 ГГц оно уже имеет значение, просто потому что за один такт сигнал в идеальных условиях будет проходить всего 10 сантиметров, а в металлическом проводнике на кристалле и того меньше.

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

Читать далее

АСУТП на молочном заводе и я: 2004 — настоящее время

Уровень сложностиСложный
Время на прочтение16 мин
Охват и читатели9.9K

АСУТП — основа современной промышленной автоматизации и инфраструктуры
управления. SCADA-система (Supervisory Control and Data Acquisition) является
частью, которая обеспечивает интерфейс между операторами и оборудованием, а
также сбор и анализ данных в реальном времени. Обычно это программный пакет,
предназначенный для обеспечения работы системы и/или разработки таких систем, —
сухое определение, которое заставляет вспоминать предмет ТАУ (теория
автоматического управления) и ПИД-регулятор. Ничего интересного — одни формулы.
Такие мысли мне тоже приходили в голову в момент распределения после завершения
учебы в университете. Так получилось, что на последнем курсе устроился работать
в классическую IT-контору, но не остался там надолго и пошёл пробовать себя на
молочный завод — в тогда ещё молодой отдел АСУТП. Что из этого вышло, далее попытаюсь
рассказать в этой статье.

Читать далее

Принципы DOD в C++: Часть 2. AoS, SoA. Мнимая панацея для быстродействия

Уровень сложностиСредний
Время на прочтение11 мин
Охват и читатели5K

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

Читать далее

Создание библиотеки на C++. Часть II: Теги, признаки и концепции

Уровень сложностиСредний
Время на прочтение13 мин
Охват и читатели6.8K

Привет! Меня зовут Николай, я C++-разработчик в SimbirSoft. Это продолжение цикла статей о проектировании библиотек на примере решения геометрических задач. В первой части мы разобрали классическое наследование с виртуальными функциями и использование шаблонов, сравнили их сильные и слабые стороны и посмотрели, какие ограничения возникают при расширении системы.

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

Материал будет полезен C++-разработчикам, которые проектируют расширяемые библиотеки и хотят лучше контролировать баланс между гибкостью, безопасностью типов и сложностью реализации. Мы разберём практический пример, поэтапно усложняя архитектуру и объясняя, зачем вводятся вспомогательные сущности и как они помогают сделать решение масштабируемым.

Для комфортного чтения потребуется уверенное знание базового синтаксиса C++, понимание шаблонов и частичной специализации, а также общее представление о статическом и динамическом полиморфизме. Текст ориентирован на разработчиков уровня middle и выше, но может быть полезен всем, кто хочет глубже разобраться в архитектурных возможностях современного C++.

Читать далее

Медицинский экзоскелет

Уровень сложностиСредний
Время на прочтение3 мин
Охват и читатели19K

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

Коротко о себе. Я инженер-конструктор с большим опытом. Работал много лет в космической отрасли. Сейчас я программист на удалёнке. Но не из-за денег я поменял работу. У меня отказали ноги из-за тяжёлой формы рассеянного склероза. К слову, со старческим он никакого отношения не имеет. Отказали не только ноги. Плохо слушаются и руки. Эту статью я набиваю голосом. Вообще, повреждение спинного мозга – это ад. Не как в кино, гораздо страшнее. Но речь пойдёт о другом.

Тема далеко не новая. Есть рынки, есть исследования, есть много всего. Но есть как минимум две причины, почему это научная фантастика. Первое это цена. В лучшем случае это цена новой машины. Второе это то, что в личное пользование это купить нельзя.

Читать далее

Blueprint VM изнутри: ~80 инструкций, которые двигают вашу игру

Уровень сложностиСложный
Время на прочтение18 мин
Охват и читатели6.3K

Каждый раз, когда вы соединяете ноды в Blueprint и нажимаете Play, Unreal Engine запускает маленький процессор. У него свои инструкции, свой стек, своя защита от бесконечных циклов. Он написан в ~4000 строках C++ и живёт в одном файле. Через него проходит каждый Event Tick, каждый Event BeginPlay, каждый вызов Blueprint-функции.

Этот процессор - Blueprint VM (Virtual Machine). И сегодня мы разберём его по винтикам.

Читать далее

Unreal Engine 5.4 + C++ + MacOS Tahoe + Android build = Build Successful

Уровень сложностиСредний
Время на прочтение4 мин
Охват и читатели8.3K

Небольшая инструкция для всех, кто работает в Unreal Engine и пишет на C++ или иных языках + компилирует файлы для Андроид.

Читать далее