Сохранёнки программиста
6.54K subscribers
1.18K photos
59 videos
10 files
1.88K links
Заметки и ссылки на будущее, чтобы изучить когда будет время.

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels

Другие наши проекты: https://tprg.ru/med
Download Telegram
Почему DuckDB обгоняет Spark на одной машине

Разбор от endjin объясняет, как встраиваемая база DuckDB превращает ноутбук в инструмент для аналитики на миллиардах строк: скорость здесь — не в масштабе, а в бережном использовании железа. Колоночное хранилище читает только нужные столбцы, векторизованное выполнение обрабатывает данные пачками по 1024–2048 значений, умещаясь в кэш процессора, а min-max-индексы пропускают целые группы строк по фильтрам. Всё параллелится на все ядра.

В тесте TPC-H DuckDB на одной машине справилась за 1 минуту 16 секунд, Spark на 32 узлах — около 8 минут. Распределённые накладные расходы дороже выигрыша от кластера.

Это не замена PostgreSQL или Kafka: один писатель, одна нода, petabyte уйдут в распределённые системы. Статья полезна тем, кто строит ETL и хочет понять, где сидит производительность.

Сохраните, если выбираете инструменты для аналитики.
👍1
На Tproger вышел разбор о том, чем пет-проект отличается от бизнеса. Разговор с Вячеславом Чикиным — серийным предпринимателем и замзавкафедрой технологического предпринимательства МФТИ.

О чём: почему бизнес начинается с чужой проблемы, а не с технологии; почему ценность решения нельзя придумать из головы (с историей про AR-очки для сборщиков трамваев, которые отвергли сами рабочие); чем предприниматель отличается от менеджера и почему тимлид — не ступенька к фаундеру; почему продукт с первыми пользователями и выручкой — ещё не бизнес, пока всё держится на одном человеке.

https://tproger.ru/articles/pochemu-vaw-pet-proekt-eshhyo-ne-biznes-a-vy-ne-predprinimatel

Реклама. Рекламодатель: МФТИ, Физтех, ИНН 5008006211, erid:2W5zFK4QUUH

@prog_stuff
«Бесполезный» if ускорил цикл в четыре раза

Автор блога purplesyringa разобрала горячий цикл своего компрессора: j = next_j[i][j], одна инструкция mov. Казалось бы, предел. На деле это pointer chasing — каждая итерация ждёт, пока из памяти придёт результат предыдущей, и весь цикл сидит на латентности, хотя вычислений почти нет.

Трюк: обернуть присваивание в if (j != next_j[i][j]). Предсказатель ветвлений считает тело маловероятным, процессор спекулятивно гонит следующие итерации параллельно, а на редком промахе сам откатывает записи. В бенчмарке 320 мкс превратились в 80.

Отдельная линия сюжета — война с компилятором: с его точки зрения такой if бессмысленен, и оптимизатор его выкидывает. Пришлось имитировать независимость условия через volatile; читатели позже нашли, что LLVM достаточно [[unlikely]]. А «правильный» рефакторинг с битовой маской вышел бы медленнее: тест бита на x86 дороже сравнения.

Полная статья: https://purplesyringa.moe/blog/quadrupling-code-performance-with-a-useless-if/

@prog_stuff
👍2
Forwarded from Веб-страница
UI-паттерны, которые скоро можно делать без JS

Если верстаете интерфейсы каждый день, я бы сохранил этот доклад Уны Кравец с CSS Day 2026 в закладки. Она разобрала, как новые CSS-возможности убирают типичный скриптовый код: sticky-заголовок прячется через scroll-state(stuck: top), а hover-тултипы собираются на атрибутах interesttarget и popover=hint — почти без JavaScript.

Ещё два момента: sibling-index() задаёт staggered-задержки прямо в CSS, а border-shape позволяет рисовать необычные формы границ вместо border-radius. Пока часть фич работает не везде — polyfill для invokers не тянет на мобильные, так что в прод пока не нёс бы. Но следить стоит: платформа берёт на себя то, за что мы раньше тащили библиотеки.

Видео доклада на YouTube.
Баг, который 15 лет жил во всех дистрибутивах Linux

Команда VEGA разобрала use-after-free на стеке ядра (CVE-2026-43499): дефект пролежал в коде с 2011 года и присутствовал в каждом крупном дистрибутиве. Для срабатывания не нужны ни привилегии, ни специальная конфигурация ядра.

Корень — в механике futex с наследованием приоритета. Функция, снимающая поток с ожидания, чистит поле pi_blocked_on у current. На обычном пути это корректно, но на «proxy»-ветке current — уже не тот поток, что спит в ожидании, и у спящего остаётся висячий указатель на фрейм собственного, уже свёрнутого стека.

Дальше — образцовая цепочка эксплуатации: контролируемые байты распыляются на освобождённый стек, подделывается структура ожидателя, обходится KASLR. В итоге — эскалация до root и выход из контейнера со стабильностью 97%. За это Google выплатил команде 92 337 долларов по программе kernelCTF.

Полная статья: https://nebusec.ai/research/ionstack-part-2/

Сохранять тем, кто хочет увидеть, как одно неверное допущение про «кто сейчас current» превращается в root на пятнадцать лет вперёд.

@prog_stuff
1👍1
На Tproger вышел обзор онлайн-магистратуры МФТИ «Технологическое предпринимательство» — глазами разработчика, который пошёл туда после 10 лет в коммерческой разработке.

О чём: почему он не стал запускать стартап без подготовки и бросал онлайн-курсы на середине; как выглядит учёба изнутри: вебинары по выходным, персональный ментор и 1000 часов работы над собственным проектом; где программа слабая (разные стадии проектов в одной группе, неровный фидбек); во сколько магистратура обойдётся в 2026 году и как проверить формат до оплаты.

Полная статья: https://tproger.ru/articles/skolko-stoit-stat-predprinimatelem-obzor-onlajn-magistratury

Реклама. Рекламодатель: МФТИ, Физтех, ИНН 5008006211, erid: 2W5zFHGdLk9

@prog_stuff
2👍1
Как переписывать историю Git без цепочки интерактивных rebase

Автор разобрал экспериментальную команду git history из Git 2.54–2.55. Она меняет старый коммит и сама перестраивает всех его потомков.

🔘 fixup встраивает staged-правку в выбранный коммит;
🔘 reword меняет сообщение, не затрагивая рабочее дерево;
🔘 split делит коммит на части по выбранным hunks.

Операции атомарны. При конфликте Git оставляет историю в исходном состоянии. Merge-коммиты пока не поддерживаются, сохранить конфликт для ручного продолжения тоже нельзя. Поэтому область применения уже, чем у интерактивного rebase.

Полная статья: https://lalitm.com/post/git-history/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Конкурентность в стиле Go, собранная поверх pthreads

Автор собрал на C знакомые по Go примитивы: мьютексы, condition variables, атомики, ограниченный пул воркеров и buffered/unbuffered channels. Затем сравнил их стоимость с реализацией Go.

🔘 атомики и свободные мьютексы работают на уровне Go или быстрее благодаря тонкой обёртке;
🔘 парковка потока и системные пробуждения замедляют condition variables в 7–10 раз;
🔘 на крупных задачах worker pool укладывается примерно в 10% от результата Go;
🔘 мелкая передача работы лучше даётся дешёвым goroutines.

Преимущество pthreads сохраняется на крупных задачах с редкой синхронизацией. Частые переключения быстро съедают выигрыш и оставляют системные потоки далеко позади runtime scheduler.

Полная статья: https://antonz.org/concurrency-in-c/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Нормальные TLS-сертификаты для внутренних сервисов

Автор настроил внутренние сервисы с сертификатами публичного ACME CA. Схема использует собственный домен, split-horizon DNS, VPN и nginx.

🔘 внешний и внутренний DNS возвращают разные адреса одного имени;
🔘 acme.sh получает сертификат и обновляет его по расписанию;
🔘 nginx слушает VPN-интерфейс и закрывает сервис от внешней сети;
🔘 SAN, CNAME и wildcard-сертификаты дают разные варианты организации имён.

Критичное место схемы — bind nginx: ошибка в адресе откроет сервис наружу. При наличии API у DNS-провайдера выпуск сертификата через DNS-01 часто требует меньше настроек, чем описанный HTTP-01.

Полная статья: https://tuxnet.dev/posts/tls-for-internal-services/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍1
Задержка в Linux: X11, Wayland, VRR и DXVK в миллисекундах

Марко Нетт собрал прибор для измерения задержки от клика до появления кадра. RP2040 эмулирует мышь с частотой опроса 1000 Гц, а фотодиод считывает яркость экрана примерно каждые 24 микросекунды. Для каждой конфигурации автор провёл три серии по сто кликов.

🔘 медианы восьми основных конфигураций уложились в 4,21–4,93 мс;
🔘 нативный X11 опередил нативный Wayland на 0,14–0,22 мс;
🔘 VRR снял 0,26–0,45 мс и уменьшил разброс результатов;
🔘 самый заметный штраф принёс XWayland: до 3,13 мс;
🔘 dxvk-low-latency дал до 0,84 мс в тесте без ограничения FPS.

Измерения сделаны на одном компьютере с RTX 4070 Super, монитором 500 Гц и KDE Plasma. На другом железе соотношение может измениться. Схемы прибора, прошивка, анализатор и сырые CSV опубликованы вместе со статьёй.

Полная статья: https://marco-nett.de/blog/measuring-input-latency-on-linux-x11-vs-wayland-vrr-dxvk/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
На Tproger вышел материал о «Точке сборки» — серии открытых вебинаров кафедры техпреда МФТИ, где основатели ИИ-стартапов делятся практикой вместо прогнозов.

О чём: почему опыт того, кто прямо сейчас собирает продукт на агентах, актуальнее любых аналитических материалов; как вайб-кодинг стал рабочим подходом в командах; что происходит с экономикой проверки гипотез, когда MVP собирается за выходные; кто выступал на первой встрече и как попасть на следующие.

Полная статья: https://tproger.ru/articles/pochemu-opyt-razrabotchikov-luchwe-prognozov-pro-ii

@prog_stuff
👍1
Тензорная библиотека на C, которую можно прочитать целиком

Большие ML-фреймворки прячут за одной строкой целую машину: раскладку данных в памяти, передачу буферов на GPU, матричное умножение, градиенты и обновление весов. Сергей Зайцев разобрал этот слой до деталей и собрал Utensil — компактную single-header-библиотеку на C.

🔘 тензор хранится как плоский массив float вместе с shape и strides, а представления разделяют данные через owner и счётчик ссылок;
🔘 каждая операция имеет CPU-реализацию и Metal kernel, состояние буферов отслеживается dirty-флагами;
🔘 матричное умножение на CPU уходит в cblas_sgemm, на GPU — в собственный kernel;
🔘 backward pass написан вручную для каждого слоя, cross-entropy считает loss и gradient за один проход;
🔘 сеть 784 → 128 → 10 на MNIST достигает примерно 97% точности на тестовой выборке.

В авторском сравнении на MacBook M1 эпоха обучения заняла 0,8 секунды, у PyTorch — около двух секунд. Этот результат относится к одной небольшой модели и конкретному компьютеру. Библиотека пока обходится без broadcasting, autograd и CUDA, а Metal привязывает ускорение к устройствам Apple. Весь путь от массива чисел до обученной сети остаётся достаточно компактным для вдумчивого чтения.

Полная статья: https://zserge.com/posts/tensor/

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Forwarded from Типичный программист
Команда Roc переписала 300 000 строк Rust на Zig и достигла паритета

Разработчики языка Roc полтора года переносили компилятор с Rust на Zig, и недавно новый догнал оригинал по возможностям. Проверка прошла на игре Rocci Bird: меньше тысячи строк на Roc теперь собирается в 31-килобайтный WebAssembly-бинарник. Старый компилятор выдавал файл более чем вдвое больше.

Забавно, что параллельно проект Bun недавно поделился опытом обратной переписи с Zig на Rust. Так что это не история «какой язык круче», а скорее редкий случай, когда две команды демонстрируют единственно правильную логику — для разных целей нужны разные инструменты. Официальный релиз Roc 0.1.0 пока не вышел. Обещают позже в этом году.

Разбор — в статье.
💊2🤪1
$ORIGIN для загрузчика ELF — без правки ядра

Динамический загрузчик в ELF прописан абсолютным путём, поэтому relocatable-бинарники для Nix, Buck и Bazel приходится собирать с костылями. Фарид Закария показал, как научить Linux подставлять интерпретатор относительно расположения самого бинарника — связкой eBPF и binfmt_misc, не трогая VFS.

🔘 программа eBPF проверяет ELF magic, берёт путь исполняемого файла и вызывает bpf_binprm_set_interp до запуска процесса;
🔘 регистрация — struct_ops плюс запись в /proc/sys/fs/binfmt_misc/register;
🔘 при обычной передаче управления через exec могут измениться argv[0], /proc/<pid>/cmdline и /proc/self/exe — здесь этих артефактов нет;
🔘 отдельный сегмент PT_INTERP_NIX включает новую механику только для явно помеченных файлов, старые бинарники работают как раньше.

Полная статья: https://fzakaria.com/2026/07/20/linux-kernel-will-support-origin-sort-of

Сохранять тем, кто собирает relocatable-бинарники и хочет увидеть, на что ещё способен eBPF.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Postgres 19 меняет сжатие по умолчанию: с pglz на LZ4

В PostgreSQL 19 планируется смена алгоритма сжатия TOAST, который четверть века по умолчанию был pglz. Разбор от Crunchy Data объясняет, что именно поменяется для TEXT, VARCHAR, BYTEA и JSONB.

🔘 в тесте автора 2000 строк по ~10 КБ сжались за 6 мс с LZ4 против 50 мс с pglz — примерно в 8 раз быстрее, распаковка близка по времени;
🔘 на одном наборе данных LZ4 дал 111 байт из 10 400 исходных (98,9% сокращения) против 186 байт у pglz, но на других данных pglz может выигрывать по размеру;
🔘 статья подробно разбирает порог TOAST около 2040 байт и порядок «сначала сжать, потом вынести наружу», наружу уходит 18-байтовый указатель;
🔘 для индексов есть практический предел: строка длиннее ~2704 байт после сжатия в индекс не помещается — повторяющаяся строка на 5000 символов ужимается до 38 байт и проходит, случайная строка на 2816 символов уже нет.

Полная статья: https://www.crunchydata.com/blog/postgres-19-compression-from-pglz-to-lz4

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

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥2
Сервис на виртуальных потоках упёрся в 420 запросов в секунду при 9% CPU

Полевой гайд на Foojay разбирает типичный инцидент с виртуальными потоками Java: сервис перестал масштабироваться на ~420 запросах в секунду, хотя процессор загружен на 9%. Арифметика сходится точно: 8 CPU × (1000 / 19 мс внешнего HTTP-вызова) ≈ 421.

Причина — pinning: виртуальный поток занимает carrier thread, и приложение незаметно превращается обратно в ограниченный пул платформенных потоков. До JDK 24 pinning часто вызывают блоки synchronized, ещё один источник — native-код.

🔘 для диагностики в JDK 21–23 есть флаг jdk.tracePinnedThreads, в JFR — событие jdk.VirtualThreadPinned;
🔘 лечение — ReentrantLock вместо synchronized, обновление JDK и отказ от удержания блокировки на время медленных сетевых вызовов.

Полная статья: https://foojay.io/today/virtual-thread-pinning-field-guide/

Сохранять тем, у кого Loom в проде и график RPS выходит на плато задолго до загрузки CPU.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
💊1
SIMD стоит знать не только авторам simdjson

Митчелл Хашимото, автор Vagrant, Terraform и терминала Ghostty, разобрал бытовой SIMD на живом коде своего терминала и свёл его к одной схеме из пяти шагов. Примеры на Zig, но идея общая для любого языка с поддержкой векторов.

Задача такая: найти конец очередного печатаемого куска текста, то есть первый кодпоинт со значением 0xF или ниже. Скалярный вариант укладывается в одну строку цикла, векторный добавляет к нему двенадцать строк без единого интринсика под конкретный процессор.

🔘 порог сравнения размножается по всем линиям через @splat, а ширину вектора отдаёт хелпер: 4 значения u32 на ARM NEON, 8 на AVX2, 16 на AVX-512;
🔘 цикл шагает сразу на целый вектор, а не на одно значение;
🔘 сравнение values > threshold выполняется для всех линий одной инструкцией процессора;
🔘 свёртка @reduce(.And, ...) отвечает, прошли ли все линии, а @bitCast и @ctz показывают номер первой упавшей;
🔘 остаток данных и процессоры без нужной ширины вектора обслуживает тот же скалярный цикл, с которого всё начиналось.

Потолок ускорения равен числу линий: в 4, 8 или 16 раз. В сквозном замере от программы до готового состояния терминала на десктопе с AVX2 вышло примерно в 5 раз. Автор отдельно объясняет, зачем писать это руками: компиляторы векторизуют мало и непредсказуемо, а неявная оптимизация может тихо исчезнуть после правки соседнего кода или обновления компилятора.

Полная статья: https://mitchellh.com/writing/everyone-should-know-simd

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

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
1
Postgres упирался в 2900 записей в секунду, не нагружая при этом ничего

Команда DBOS разобрала, откуда у LISTEN/NOTIFY репутация нерабочего при нагрузке механизма, и переписала свой стриминг до 60 тысяч записей в секунду на одном сервере.

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

Причина в том, что коммит транзакции с NOTIFY берёт глобальный эксклюзивный лок и держит его до конца коммита вместе с fsync. Postgres обещает доставлять уведомления в порядке коммитов, а сам порядок известен только когда коммит завершён: лок решает это противоречие ценой полной сериализации. Групповой коммит при этом отключается, и записи идут строго по одной.

🔘 патч, который ждут в Postgres 19, глобальный лок не убирает. Он оптимизирует более узкий случай, когда каналов много и каждый слушатель ждёт свой;
🔘 обход: копить уведомления в памяти и сбрасывать пачкой одной транзакцией, тогда лок берётся раз на пачку, а не на каждую запись;
🔘 плата за это — уведомления, потерянные при падении процесса, поэтому читатели вдобавок редко опрашивают таблицу как запасной путь;
🔘 после переделки упор идёт уже в процессор базы, а не в блокировку.

Про задержку авторы пишут 15–100 мс, но по их же графику это диапазон для нагрузки до 40 тысяч записей в секунду. Ближе к 60 тысячам медиана уходит примерно к 0,5 с, а 99-й перцентиль к секунде. Код бенчмарка выложен, конкретный инстанс базы в статье не назван.

Полная статья: https://www.dbos.dev/blog/postgres-listen-notify-scalability

Сохранять тем, кто держит очередь или пуш-уведомления прямо в Postgres и однажды упрётся в потолок, которого не видно ни в одном мониторинге.

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Админский токен GitHub уехал в прошивку камеры вместе со сборкой веб-интерфейса

Автор блога разобрал прошивку камеры видеонаблюдения Hanwha Vision, бывшей Samsung Techwin, и нашёл внутри токен GitHub с правами администратора на сотни репозиториев компании.

Путь до находки:

🔘 внешний архив прошивки открывается паролем HTW плюс номер модели, внутри лежит ещё один зашифрованный fwimage.tgz;
🔘 ключ AES-256-CBC собирается в момент запуска из XOR-таблицы внутри бинарника fwupgrader, вектор инициализации лежит там же открытым текстом, а сам fwupgrader просто вызывает консольный openssl;
🔘 распакованный rootfs автор прогнал через trufflehog, и токен нашёлся примерно в тридцати файлах;
🔘 попал он туда из-за сборки интерфейса на Vite: одной переменной при сборке присвоили целиком process.env, поэтому окружение CI-задачи целиком записалось в файлы интерфейса вместе с токеном npm, служебными переменными Kubernetes и внутренними адресами.

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

Чтобы понять масштаб, автор скачал около 500 прошивок примерно из 600 моделей, расшифровал тем же способом 62% и нашёл токен только в трёх, причём везде один и тот же. Hanwha ответили на письмо за 12 часов и отозвали токен.

Отдельная деталь: среди служебных переменных оказались адреса из диапазона 55.101.x.x, который принадлежит Министерству обороны США. Компания ответила, что не знала об этом и унаследовала схему адресации от Samsung Techwin, а теперь собирается её менять.

Полная статья: https://hhh.hn/hanwha-github-token/

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

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯4
Потребитель получил ответ 204, закоммитил offset, а задачу через миллисекунды отклонили

Сахан Серасингхе 12 июля разобрал класс потерь в событийных системах, где сообщение пропадает без исключения, без строчки в логе и без попадания в очередь недоставленных. Он называет это разрывом подтверждения: приём запроса подтверждён, а работа так и не началась.

Доставка at-least-once держится на повторах и идемпотентных потребителях, и оба механизма опираются на одно допущение: если обработка не удалась, потребитель об этом узнает. Но ответ 202 Accepted значит «запрос принят», а не «работа выполнена», и даже 204 No Content бывает двусмысленным. Коммит offset при этом означает куда более сильное: все сообщения до N обработаны полностью и повторять их нельзя.

🔘 типичный сценарий: потребитель отправляет задачу, получает 204, коммитит offset, а управляющий слой через миллисекунды отклоняет её из-за квоты, admission control или переполнения внутренней очереди;
🔘 проверка только на err != nil опасна, потому что самый разрушительный исход выглядит как nil;
🔘 граница может быть любой асинхронной: брокер очередей, workflow engine, фоновый обработчик, HTTP-диспетчер;
🔘 повторы, идемпотентность и транзакция брокера тут не спасают, раз подтверждается только приём задачи;
🔘 надёжнее подтверждать запуск отдельно: чтение после записи или опрос по correlation ID, а явный отказ считать ошибкой;
🔘 повторы ограничивают бюджетом, а после его исчерпания шлют алерт или отправляют сообщение в очередь недоставленных.

Автор отдельно оговаривает обратный риск. Ошибка самой проверки состояния не должна автоматически порождать новую отправку, иначе вместо потерянного сообщения появится дубликат, и вся идемпотентность на стороне обработчика уедет в мусор.

Полная статья: https://sahansera.dev/the-acknowledgment-gap/

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

@prog_stuff
Please open Telegram to view this post
VIEW IN TELEGRAM