Обновить
-1

Пользователь

Отправить сообщение

Чёрная магия C++: Быстрый кольцевой буфер

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

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

Как правило, кольцевой буфер реализуется через списки, вроде std::list или std::deque, либо через плоские массивы, вроде std::vector или boost::circular_buffer. Но ни одна реализация не гарантирует непрерывность и упорядоченность одновременно. В данной статье я расскажу про реализацию буфера через трюк с виртуальной памятью, сохраняющую упорядоченность элементов в непрерывной ограниченной области памяти.

Читать далее

Native AOT заставил меня переписать весь .NET проект

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

Мне хотелось, чтобы знакомство с HydraScript выглядело просто: скачал интерпретатор, запустил скрипт. Сомнительно предлагать человеку сначала установить подходящий .NET Runtime ради моего языка программирования.

Переход на Native AOT поначалу казался правкой .csproj. Включил настройку, опубликовал бинарник, пошёл дальше. На практике пришлось переписать всё. Досталось даже интеграционным тестам. А в процессе рефакторинга ещё и пропали логи.

Читать далее

А чё, так можно было? Три места в.NET, которые не развидеть

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

Пустой наследник Random работает медленнее родителя. string[] и object[] оказываются одним объектом. А Matrix4x4 до сих пор держит шестнадцать полей float вместо четырёх векторов.

Ни одно из трёх уже не переделать, и на то есть причины.

Читать далее

А чё, так можно было? Опечатка в исходниках .NET, которой больше 20 лет

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

В System.Random кто-то двадцать лет назад написал 21 вместо 31. Опечатку заметили, разобрали и оставили как есть — исправить, и new Random(42) начнёт выдавать другие числа.

А ещё new Random() и new Random(42) — вообще разные генераторы. Разница на некоторых методах доходит до 10 раз.

Читать далее

А чё, так можно было? Три недооценённых атрибута.NET

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

Три атрибута, которые меняют результат компиляции. Один запускает метод раньше Main. Второй передаёт текст выражения вместо результата. Третий ускоряет stackalloc в 50 раз.

Все три описаны в документации и применяются внутри .NET. А в рабочем коде я их ни разу не видел.

Читать далее

А чё, так можно было? int == -int

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

Есть число, которое не меняется от смены знака. Минус перед ним ничего не делает, а модуля у него не существует: Math.Abs бросает исключение.

Это int.MinValue. И это ещё не всё, что он умеет.

Читать далее

А чё, так можно было? Приватное поле за 0,25 наносекунды

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

Чтение приватного поля через рефлексию занимает 8,96 наносекунды и выделяет 24 байта в куче. Тот же доступ без рефлексии — 0,25 наносекунды и ноль байт.

Разница в 35,8 раза, а на .NET 8 она доходила до 108. Способ появился в .NET 8, применяется внутри библиотеки классов и работает без генерации кода.

Читать далее

А чё, так можно было? Dictionary == List

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

Ключ-структура из числа и строки. Поиск по словарю на 10 000 таких ключей занимает 74 975 микросекунд. Тот же ключ, объявленный record struct, — 3,354 микросекунды.

Разница в 22 354 раза, и берётся она не из сравнения ключей.

Читать далее

А чё, так можно было? Недокументированный C#

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

В C# есть четыре ключевых слова, которых нет в документации. Компилятор их принимает.

Одно из них собирается на любой машине, а выполняется только на Windows. На Linux та же сборка падает. Дальше — как объект меняет свой тип на ходу и что на самом деле происходит при вызове метода у пустой ссылки.

Читать далее

А чё, так можно было? Порядок полей = 1,8× к скорости

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

Класс без единого поля занимает 24 байта, с двумя полями int — те же 24, а с тремя — уже 32.

В структуре достаточно поменять местами два поля, и её размер уменьшится с 24 байт до 16, а обход массива ускорится в 1,8 раза.

Читать далее

А чё, так можно было? new ≠ память

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

В .NET есть метод, который всегда возвращает false. Есть очистка списка, которая ничего не очищает. И есть new, после которого в куче пусто.

Разберем пять таких мест: что написано в исходнике, что от него остаётся в машинном коде и зачем так сделано.

Читать далее

А чё, так можно было? +1 ключ = ×12 к скорости

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

В словарь добавляют 101 ключ — поиск занимает 8 763 наносекунды. Добавляют 102-й — 718.

Ключей стало больше, а времени в 12 раз меньше. Разбираемся, что происходит на 102-й вставке.

Читать далее

JSON умеет считать сам себя — удобно, как в Excel, но без вранья с типами

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

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

Читать далее

MarkMello v0.4.0: развитие MD-редактора

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

Всем привет!

В мае я опубликовал на Хабре первую статью о MarkMello (легкий MD-просмотрщик). Изначальная задача была простой: сделать лёгкое приложение, которое быстро открывает локальный Markdown-файл сразу в режиме чтения.

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

Читать далее

Бенчмаркая сортировку строк: подстава с дефолтным компаратором — ×5

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

Сортировка строк без компаратора работает не так, как кажется, и заметно дольше.

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

Читать далее

Бенчмаркая LINQ: подстава с OrderBy — одно условие и полная сортировка

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

Одни вызовы после OrderBy проходят набор один раз, другие приводят к полной сортировке. По коду разницы не видно.

Давайте проверим счётчиком обращений к компаратору — на четырёх машинах и четырёх рантаймах.

Читать далее

Бенчмаркая Span.Sort: выбрал компаратор-структуру — и получил 88 байт на вызов

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

Перегрузка Span.Sort с компаратором-структурой должна была работать быстрее обычной. Замер показал обратное: памяти она расходует больше всех, а времени тратит больше, чем компаратор-класс — на .NET 8, 9 и 10.

В .NET 11 результат меняется, но не везде.

Читать далее

Бенчмаркая try/finally: один finally — и метод в 6,45 раза медленнее

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

Один try/finally внутри метода — и он работает в разы медленнее. Сам блок тут ни при чём, он не выполняет ни одной лишней инструкции.

Причина в решении JIT. В .NET 10 его поменяли — но не для всех методов и не при любых настройках.

Читать далее

Бенчмаркая Enumerable.Chunk: почему батчей меньше, а проход до ×2,7 дольше

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

Chunk делит коллекцию на массивы — одна строка кода. Но есть размер чанка, после которого он замедляется в разы при тех же данных и той же памяти. А на массиве и на List<int> внутри разный код, и в самой строке этого не видно.

Читать далее

Бенчмаркая StringBuilder: подстава на длинном тексте

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

StringBuilder делит текст на чанки по 8000 символов — вчетверо ниже порога кучи больших объектов. Запас такой, что попасть туда невозможно.

Но чанк на 400 КБ в этой куче возможен и получить его можно разными способами.

Читать далее
1
23 ...

Информация

В рейтинге
4 715-й
Зарегистрирован
Активность