← На главную

SIMD проще, чем кажется: ускорение до 5x, а на AVX-512 до 16x

22.07.2026 17:48 · hackernews

SIMD окружён репутацией чего-то сложного. Многие хорошие инженеры списывают его как нишевую оптимизацию для супер-высокопроизводительного софта, бесполезную в обычной работе. Это ошибка. SIMD может быть простым, а стандартный паттерн «обрабатываем N значений за раз» почти всегда одинаков. Выучив базу, писать SIMD так же легко, как обычный for-цикл. А когда нелегко — лучше пока пропустить. Каждый разработчик должен знать хотя бы это.

SIMD позволяет CPU работать с несколькими значениями параллельно. Вместо сравнения одного байта — сравнить 4, 8 или больше одной инструкцией. Стандартный for (byte in bytes) превращается в for (8 byte chunk in bytes). Требование одно: данных должно быть много (сотни, тысячи, миллионы байт). Для десятков байт овчинка выделки не стоит.

У такого SIMD-кода пять шагов. Первый: размножить константы по всем «полосам» (lanes) вектора и инициализировать аккумуляторы, если нужно. Второй: цикл, загружающий за раз целый вектор (4, 8 или 16 значений). Третий: выполнить операцию (сравнение, сложение и т.д.) сразу над всеми полосами. Четвёртый: свернуть результат вектора в то, что нужно алгоритму (найти индекс первого совпадения, посчитать сумму). Пятый: остаток данных, не влезший в полный вектор, обработать обычным скалярным циклом (scalar tail).

Пример из проекта Ghostty: нужно найти в массиве codepoints первый управляющий символ (значение ≤ 0xF). Скалярный код — однострочный while. SIMD-версия на Zig в 12 строк ускоряет этот поиск до 5x на реальной задаче терминала и до 16x теоретически на AVX-512. В коде: сначала определяется число полос (4 на ARM, 8 на AVX2, 16 на AVX-512), значение 0xF размножается в вектор, затем цикл грузит векторы, сравнивает их с порогом одной командой, а редукция через @reduce и @ctz находит позицию первого «плохого» символа. Остаток добивает скалярный хвост.

Почему компилятор сам это не делает? Иногда делает (автовекторизация простых циклов), но в целом компиляторы плохо справляются и часто упускают возможности. Если важен предсказуемый прирост в 5x, лучше написать SIMD вручную, чем надеяться на оптимизатор.

Каждый разработчик должен узнавать возможность применить SIMD в горячем цикле, который сканирует, сравнивает или преобразует большие объёмы данных. Паттерн регулярный и привычный. С хорошей поддержкой языка не нужно знать ассемблер или особенности CPU.

Читать оригинал →