en
Feedback
Rust

Rust

Open in Telegram

Полезный контент по программированию на Rust

Show more
2 230
Subscribers
+324 hours
+37 days
+230 days
Posts Archive
Rust
2 230
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Go📌 https://max.ru/golang_lib Библиотека Go (Golang) разработчика Программирование React📌 https://max.ru/react_lib React Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

Rust
2 230
📦 Иллюзия объектов: Как мы морим процессор голодом Представьте, что вы пишете симуляцию (или игру). По заветам ООП вы создаете сущность:

struct Particle {
    position: [f32; 3], // 12 байт
    velocity: [f32; 3], // 12 байт
    color: [u8; 4],     // 4 байта
    life: f32,          // 4 байта
    name: String,       // 24 байта
} 
// Итого: 56 байт
Затем складываете их в массив: Vec<Particle>. Это называется Array of Structs (AoS). Теперь нам нужно в цикле обновить позицию (position += velocity). Нам нужны только 24 байта из 56. Но процессор так не умеет! Процессор читает память из RAM в свой сверхбыстрый L1 кэш кусками по 64 байта (Cache Line). Когда он берет первую частицу, он затягивает в кэш её position, velocity, а заодно color, life и половину name. Результат: 1. Cache Miss: Больше половины кэша забито мусором (color, name), который в данном цикле не нужен. Процессору приходится постоянно бегать в медленную RAM за новыми частицами. 2. Bandwidth: Вы сжигаете пропускную способность памяти впустую. Мы пишем код для людей, забывая, что исполнять его железу. Железо любит однородные, плотно упакованные данные. Как это исправить? Об этом в следующем посте. #rust #architecture #dop #performance #cpu 👉 @rust_lib

Rust
2 230
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

Rust
2 230
💻Angular — один из самых строгих и системных инструментов разработки пользовательских интерфейсов. Его выбирают крупные комп
💻Angular — один из самых строгих и системных инструментов разработки пользовательских интерфейсов. Его выбирают крупные компании, где важны масштабируемость, предсказуемость кода и возможность развивать продукт долгие годы. Мы расскажем вам как работать с этим инструментом. Записывайтесь на открытые уроки в преддверии старта курса «Angular-разработчик»: 📆26 марта в 20:00 МСК на открытом уроке разберём, как LLM ускоряют фронтенд-разработку. Покажем их развитие, подготовим Angular-проект к работе с ИИ, создадим приложение и обсудим, где ИИ реально помогает разработчику. 📆9 апреля в 20:00 МСК на открытом уроке разберём сигналы в Angular: создадим реактивную форму с валидацией, обсудим управление состоянием и сравним с подходом на RxJS. 📆21 апреля в 20:00 МСК разберём архитектуру Angular-приложения: слои, feature-подход, разделение UI, логики и API, а также паттерны и структуру реального проекта. Подробности об уроках и регистрация: https://vk.cc/cVBvJD Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Rust
2 230
Wgpu - это безопасная и переносимая графическая библиотека для Rust, основанная на API WebGPU. Она подходит для универсальной
Wgpu - это безопасная и переносимая графическая библиотека для Rust, основанная на API WebGPU. Она подходит для универсальной графики и вычислений на GPU. Приложения, использующие wgpu, могут работать нативно на Vulkan, Metal, DirectX 12 и OpenGL ES, а также в браузерах через WebAssembly на WebGPU и WebGL2. https://wgpu.rs/ https://github.com/gfx-rs/wgpu 👉 @rust_lib

Rust
2 230
🥷 Кража во спасение: Work Stealing в Tokio Если вы используете tokio::main, вы запускаете многопоточный рантайм (Multi-Threaded Scheduler). Под капотом создается пул потоков (воркеров), обычно по числу ядер процессора. Как честно распределить 100,000 задач между 8 потоками, чтобы никто не простаивал и не было узкого горлышка (bottleneck)? Если сделать одну Глобальную очередь (Global Queue), куда смотрят все потоки, они передерутся за Мьютекс (Mutex contention). Производительность рухнет. Поэтому Tokio использует Локальные очереди (Local Queues): 1. У каждого потока-воркера есть своя личная очередь задач (до 256 штук). 2. Воркер берет задачи только из своей очереди. Никаких блокировок! Это невероятно быстро. 3. Новые задачи, порожденные текущей (tokio::spawn), падают в локальную очередь этого же потока. А что если один поток закончил все задачи, а у другого их еще 200? Включается Work Stealing (Кража работы): 1. Скучающий воркер смотрит в локальные очереди других потоков. 2. Он находит самую загруженную очередь и втихаря "крадет" ровно половину её задач. 3. Забирает их себе в локальную очередь и начинает молотить. Это гениальный компромисс: 99% времени потоки работают без блокировок, и лишь изредка (при перекосе баланса) происходит синхронизация для кражи. Именно поэтому Tokio выдерживает миллионы RPS на мощных серверах. #rust #tokio #architecture #multithreading #work_stealing 👉 @rust_lib

Rust
2 230
🚀 Подборка полезных IT каналов в Max Системное администрирование, DevOps 📌 https://max.ru/i_odmin Все для системного администратора https://max.ru/bash_srv Bash Советы https://max.ru/sysadminof Книги для админов, полезные материалы https://max.ru/i_odmin_book Библиотека Системного Администратора https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др. 1C разработка 📌 https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С Программирование C++📌 https://max.ru/cpp_lib Библиотека C/C++ разработчика Программирование Python 📌 https://max.ru/python_of Python академия. https://max.ru/BookPython Библиотека Python разработчика Java разработка 📌 https://max.ru/bookjava Библиотека Java разработчика GitHub Сообщество 📌 https://max.ru/githublib Интересное из GitHub Базы данных (Data Base) 📌 https://max.ru/database_info Все про базы данных Фронтенд разработка 📌 https://max.ru/frontend_1 Подборки для frontend разработчиков Библиотеки 📌 https://max.ru/programmist_of Книги по программированию https://max.ru/proglb Библиотека программиста https://max.ru/bfbook Книги для программистов Программирование 📌 https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT https://max.ru/php_lib Библиотека PHP программиста 👨🏼‍💻👩‍💻 Шутки программистов 📌 https://max.ru/itumor Шутки программистов Защита, взлом, безопасность 📌 https://max.ru/thehaking Канал о кибербезопасности https://max.ru/xakkep_1 Хакер Free Книги, статьи для дизайнеров 📌 https://max.ru/odesigners Статьи, книги для дизайнеров Математика 📌 https://max.ru/Pomatematike Канал по математике https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике Вакансии 📌 https://max.ru/progjob Вакансии в IT Мир технологий 📌 https://max.ru/mir_teh Канал для любознательных Бонус 📌 https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга https://max.ru/mockva_life Свежие новости Москвы

Rust
2 230
Хватит дергать: Waker и паттерн пейджера Окей, Future вернула управление (сказала Poll::Pending). Но как рантайм узнает, что данные по сети пришли и пора снова вызвать poll()? Если он будет постоянно опрашивать все Future в цикле (while loop), ваш CPU улетит в космос на 100% загрузке. Здесь на сцену выходят Executor, Reactor и Waker. • Executor - это менеджер задач. Он берет Future и вызывает у нее poll(). • Reactor - это слушатель ОС (обертка над epoll в Linux, kqueue в macOS или IOCP в Windows). Он ждет событий от сетевой карты или диска. • Waker - это тот самый пейджер, который выдают в бургерной. Как это работает: 1. Future делает сетевой запрос и понимает, что данных еще нет. 2. Она регистрирует этот запрос в Reactor и отдает ему свой Waker (колбэк, в котором зашит ID этой Future). 3. Future возвращает Pending. Executor забывает про неё и идет выполнять другие задачи. 4. ...проходит время... Сетевая карта получает пакеты. ОС дергает epoll. 5. Reactor видит: "Ага, пришли данные для сокета X". Он берет Waker, привязанный к этому сокету, и вызывает waker.wake(). 6. Waker сигнализирует Executor'у: "Задача #42 готова, помести её обратно в очередь на выполнение". 7. Executor снова вызывает poll(), и стейт-машина делает следующий шаг. Никакого холостого хода CPU. Только чистая событийная архитектура. #rust #async #waker #tokio #epoll 👉 @rust_lib

Rust
2 230
🪄 Разрушаем магию: Твоя Future - это просто enum Многие приходят в Rust из Go или Erlang и думают, что async запускает легковесный поток (горутину). Забудьте. Асинхронный Rust работает совершенно иначе - он не аллоцирует стек под каждую задачу. Когда вы пишете async fn, компилятор превращает вашу функцию в конечный автомат (State Machine). Смотрим код:

async fn fetch_data() {
    let req = build_request();
    let resp = send(req).await; // <-- Точка остановки 1
    process(resp).await;        // <-- Точка остановки 2
}

Под капотом LLVM генерирует невидимый enum, который хранит локальные переменные между вызовами .await:

// Примерно так это видит компилятор:
enum FetchDataStateMachine {
    Start,
    WaitSend { req: Request }, // Храним локальные переменные
    WaitProcess { resp: Response },
    Done,
}

Когда рантайм вызывает метод poll() у этой Future: 1. Выполняется кусок кода до первого .await. 2. Состояние переключается (в WaitSend). 3. Управление возвращается обратно в рантайм! (Никакого блокирования потока). Почему это круто? Такой enum весит считанные байты. Вы можете создать миллион таких Future на обычном ноутбуке, и они займут всего пару десятков мегабайт оперативки. Никакая ОС не позволит вам создать миллион настоящих потоков. #rust #async #under_the_hood #future 👉 @rust_lib

Rust
2 230
🚀 Portable SIMD: Пишем один раз, работает везде В прошлом посте вы видели ужас ручных интринсиков. Представьте, что вам нужно поддерживать SSE2, AVX2, AVX-512, да еще и ARM NEON для макбуков. Это ад из cfg_if и дублирования кода. Rust сообщество решает эту проблему. Встречайте Portable SIMD (сейчас это крейт portable-simd или фича #![feature(portable_simd)] в nightly). Идея: мы используем абстрактные типы "широких" чисел, а компилятор сам мапит их на лучшие инструкции целевой платформы. Выглядит это потрясающе чисто:

#![feature(portable_simd)] // Нужен nightly Rust
use std::simd::{f32x8, Simd};

fn add_portable(a: &[f32], b: &[f32], out: &mut [f32]) {
    // Берем чанки по 8 элементов
    let chunks_a = a.chunks_exact(8);
    let chunks_b = b.chunks_exact(8);
    let chunks_out = out.chunks_exact_mut(8);

    for ((slice_a, slice_b), slice_out) in chunks_a.zip(chunks_b).zip(chunks_out) {
        // Превращаем слайсы в SIMD-вектора (почти бесплатно)
        let vec_a = f32x8::from_slice(slice_a);
        let vec_b = f32x8::from_slice(slice_b);

        // Обычный оператор "+" работает как SIMD сложение!
        let vec_res = vec_a + vec_b;

        // Записываем обратно
        vec_res.copy_to_slice(slice_out);
    }
    // + нужно обработать "хвост", если длина не кратна 8
}

Никакого unsafe! Никаких _mm256_ugly_names! Если вы компилируете это под AVX2 - будет AVX2. Под ARM NEON - будет NEON. Это будущее высокопроизводительного Rust. Ждем стабилизации. #rust #simd #nightly #future 👉 @rust_lib

Rust
2 230
💀 Хардкорный режим: std::arch и интринсики Автовекторизация не сработала? Алгоритм слишком сложен для LLVM? Придется марать руки. Встречайте std::arch. Это модуль, дающий доступ к конкретным инструкциям процессора (интринсикам). Это очень unsafe. Это не портабельно (код для x86 не заработает на ARM M1). Как выглядит сложение массивов на AVX2 (x86_64):

#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

// Атрибут важен! Он говорит компилятору, что внутри этой функции
// можно использовать 256-битные регистры.
#[target_feature(enable = "avx2")]
unsafe fn add_avx2(a: &[f32], b: &[f32], out: &mut [f32]) {
    // Мы обязаны обрабатывать данные чанками по 8 штук.
    // (Опустим проверки длин и обработку "хвостов" для краткости)
    for i in (0..a.len()).step_by(8) {
        // Загружаем 8 float'ов в 256-битный регистр
        let vec_a = _mm256_loadu_ps(a.as_ptr().add(i));
        let vec_b = _mm256_loadu_ps(b.as_ptr().add(i));

        // ОДНА инструкция сложения для 8 пар чисел
        let vec_res = _mm256_add_ps(vec_a, vec_b);

        // Выгружаем обратно в память
        _mm256_storeu_ps(out.as_mut_ptr().add(i), vec_res);
    }
}

Главная опасность: Если вы вызовете эту функцию на старом процессоре (без AVX2), программа упадет с ошибкой "Illegal Instruction". Решение: Runtime detection. Вы должны проверять фичи процессора в рантайме.

fn add_smart(a: &[f32], b: &[f32], out: &mut [f32]) {
    if is_x86_feature_detected!("avx2") {
        // Безопасно, мы проверили
        unsafe { add_avx2(a, b, out) }; 
    } else {
        // Медленный фоллбэк для старого железа
        add_scalar(a, b, out);
    }
}

Это сложно, больно, но дает максимальный контроль над железом. #rust #simd #unsafe #lowlevel #intrinsics 👉 @rust_lib

Rust
2 230
🏎️ SIMD для ленивых: Автовекторизация в Rust SIMD - это когда процессор одной инструкцией складывает не два числа, а сразу 4, 8 или 16. Многие думают, что SIMD это сложно и требует unsafe. Но лучший SIMD тот, который LLVM написал за вас. Допустим, у вас есть цикл:

pub fn add_arrays(a: &[f32], b: &[f32], out: &mut [f32]) {
    // Простые смертные пишут так:
    for i in 0..a.len() {
        out[i] = a[i] + b[i];
    }
}

Если вы скомпилируете это в релизе для x86_64, компилятор сгенерирует инструкции SSE2 (обрабатывая по 4 числа f32 за раз). Почему? Потому что SSE2 гарантированно есть на всех 64-битных процессорах Intel/AMD. Как сделать еще быстрее? Если вы знаете, что ваш код будет работать на современном железе, разрешите компилятору использовать AVX2 (по 8 чисел f32).

RUSTFLAGS="-C target-cpu=native" cargo build --release

Но есть нюанс: Компилятор очень осторожен. Он не применит SIMD, если: 1. Есть риск паники. Если срезы разной длины, компилятор вставит проверки границ (bounds check) внутри цикла. Это убивает векторизацию. • Лечение: Используйте итераторы (zip) или явно проверяйте длины до цикла и используйте assert!, чтобы дать хинт оптимизатору. 2. Есть риск алиасинга. Если out пересекается в памяти с a или b. • Лечение: Rust тут молодец, его правила заимствования гарантируют отсутствие мутабельного алиасинга. Всегда смотрите в ассемблер (cargo-show-asm), чтобы убедиться, что цикл развернулся в SIMD-инструкции (ищите что-то вроде vaddps вместо addss). #rust #simd #performance #llvm #autovectorization 👉 @rust_lib

Rust
2 230
🚫 Убиваем if: Branchless Programming Самый быстрый if - это отсутствие if. Иногда можно заменить ветвление на арифметику. Это гарантирует отсутствие Pipeline Flush, так как поток инструкций линейный. Задача: Вернуть a, если condition true, и b, если false. С ветвлением:

let result = if condition { a } else { b }; 
// Генерирует инструкцию перехода (JMP/JNE) -> Риск misprediction

Branchless (без ветвления): В Rust bool можно скастить в u8 (true = 1, false = 0).

// (a * 1) + (b * 0) = a
// (a * 0) + (b * 1) = b
let result = a * (condition as i32) + b * (!condition as i32);

Но подождите! Современные компиляторы часто делают это сами. Они превращают простой if в инструкцию CMOV (Conditional Move). Это инструкция процессора: "Скопируй данные, если флаг выставлен". Это не ветвление, это просто копирование по условию. Как проверить? Смотрите в ассемблер (через godbolt или cargo-show-asm). Если видите cmov - поздравляю, у вас branchless код, и он будет работать быстро, даже если данные случайны. Если видите jle / jne - это прыжок. Совет: Пишите читаемый код. И только если профайлер показывает, что BPU захлебывается в горячем цикле - переписывайте на арифметику. #rust #assembly #branchless #performance 👉 @rust_lib

Rust
2 230
👣 Rust выбирают там, где цена ошибки — падение продакшена, утечки памяти и неконтролируемая многопоточность. Курс «Rust Developer. Professional» — следующий шаг после базового знакомства с Rust или работы на других языках. Вы разберёте Best Practices языка, асинхронность, архитектуру и многопоточность, научитесь использовать экосистему библиотек и писать отказоустойчивое, высокопроизводительное ПО. ❗️ Программа ориентирована на практику и инженерное мышление. Преподаватели — практикующие эксперты, работающие с системным и высоконагруженным ПО. Курс регулярно обновляется под реальные требования рынка. ▶️Старт курса 25 февраля. Курс доступен в рассрочку. Пройдите короткое вступительное тестирование и получите специальные условия на обучение: https://vk.cc/cUxQhX Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

Rust
2 230
🥶 Холодный расчет: #[cold] и likely Компилятор Rust (LLVM) очень умный, но иногда мы знаем о поведении программы больше, чем он. Мы можем подсказать ему, какая ветка кода будет выполняться чаще. 1. Атрибут #[cold] Идеально для обработки ошибок. Вы говорите компилятору: "Сюда мы будем заходить крайне редко". Компилятор сдвинет этот код в "дальний угол" бинарника, чтобы "горячий" путь шел линейно в памяти (это улучшает работу кэша инструкций и BPU).

#[cold] // <-- Подсказка
fn handle_fatal_error() {
    // Логирование, паника, сложная логика...
}

fn process(data: &str) {
    if let Err(_) = parse(data) {
        handle_fatal_error(); // Компилятор знает, что это маловероятно
        return;
    }
    // Happy path идет дальше линейно
}

2. likely / unlikely (Nightly / Crates) В стабильном Rust пока нет std::intrinsics::likely, но есть крейт likely или хаки. Это прямая инструкция процессору через LLVM.

// С крейтом `likely`
if likely(x > 0) {
    // Оптимизатор будет строить код так, 
    // будто это условие почти всегда true
}

Используйте #[cold] для ошибок и граничных случаев. Это стабильно, бесплатно и делает код чище. #rust #optimization #llvm #hints 👉 @rust_lib

Rust
2 230
🔮 Ты не пройдешь: Магия предсказателя ветвлений Вы когда-нибудь задумывались, почему обработка отсортированного массива чисел происходит в разы быстрее, чем случайного, даже если логика одна и та же? Всё дело в конвейере (pipeline). Процессор выполняет инструкции не по одной, а потоком: пока одна декодируется, другая уже выполняется. Но тут появляется if (ветвление). Процессор не знает, пойдет код в then или в else, пока не вычислит условие. Но ждать он не может - конвейер встанет. Поэтому он угадывает. • Угадал? Выполнение продолжается без задержек. • Не угадал? Происходит Pipeline Flush. Процессор выбрасывает все инструкции, которые успел "набрать" по неверному пути, и начинает заново с правильного адреса. Это огромная потеря тактов (10-20 циклов CPU). Пример на Rust:

// Если data отсортирован: T T T T T F F F F F (паттерн ясен)
// Если data случайный: T F T T F F T F (паттерн непредсказуем)
for &x in &data {
    if x > 128 {
        sum += x;
    }
}

На случайных данных BPU ошибается в 50% случаев. На сортированных почти никогда. Вывод: Чем предсказуемее ваши данные, тем быстрее работает ваш код. Иногда data.sort() перед обработкой окупается с лихвой. #rust #cpu #lowlevel #performance #branch_prediction 👉 @rust_lib

Rust
2 230
👣 Многопоточность — одна из самых сложных тем в разработке. Гонки данных, дедлоки, неопределённое поведение в продакшене. Во многих языках это цена за производительность. На открытом уроке разберём, как Rust решает проблемы конкурентности на уровне языка. Вы шаг за шагом напишете пул потоков с нуля и увидите, как система владения и типы Send и Sync предотвращают гонки данных ещё на этапе компиляции. ❗️ Мы рассмотрим архитектуру worker-потоков, использование каналов и умных указателей, а также корректное завершение работы пула и обработку ошибок. Вы поймёте, когда есть смысл писать пул самостоятельно, а когда лучше использовать готовые библиотеки. В итоге у вас будет готовый компонент, который можно применять в реальных проектах — от сервисов до высоконагруженных приложений. 🔴 Встречаемся 12 февраля в 20:00 МСК в преддверии старта курса «Rust Developer. Professional». 👉 Зарегистрируйтесь, чтобы не пропустить: https://vk.cc/cUiWUD Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Rust
2 230
🗝 Турбируем HashMap Стандартный std::collections::HashMap в Rust использует алгоритм хэширования SipHash. Почему? Он криптографически стоек к HashDoS атакам (когда злоумышленник подбирает ключи так, чтобы все они попадали в один бакет, превращая мапу в связный список и убивая CPU). Но SipHash медленный. Если вы решаете алгоритмические задачи, пишете геймдев или у вас внутренний сервис без внешнего доступа - вам не нужна защита от DoS. Вам нужна скорость. Используйте сторонние хэшеры. Самые популярные: 1. FxHash (rustc-hash) - используется внутри самого компилятора Rust и Firefox. Молниеносно быстрый для коротких ключей (integers). 2. AHash - современный, быстрый, использует аппаратные инструкции AES. Пример с крейтом rustc-hash:

use rustc_hash::FxHashMap;

// Это та же HashMap, но с быстрым хэшером
let mut map: FxHashMap<u32, &str> = FxHashMap::default();

Прирост производительности на операциях вставки/поиска может достигать 2x-3x на простых ключах. Итог: • Backend наружу? Оставляем дефолтный SipHash. • GameDev / Algo / Internal Data Processing? Ставим FxHash или AHash. #rust #performance #hashmap #external_crates 👉 @rust_lib

Rust
2 230
⚡️ Забудь про RefCell для примитивов Вам нужно изменить поле внутри неизменяемой структуры (&self). Рука тянется к RefCell? Стоп. RefCell имеет оверхед: 1. Хранит счетчик заимствований (borrow count). 2. В рантайме проверяет правила (может паниковать!). Если ваш тип реализует Copy (числа, bool, маленькие структуры) - используйте Cell. В чем магия Cell? У него нет никакого рантайм-оверхеда. Вообще. Он не проверяет заимствования. Он работает так: "Я даю тебе копию значения" (get) или "Я заменяю значение целиком" (set). Вы не можете получить ссылку (&) на содержимое Cell, поэтому правила Rust не нарушаются.

use std::cell::Cell;

struct Metric {
    count: Cell<u64>, // Zero overhead
}

impl Metric {
    fn inc(&self) {
        // Мы меняем значение по неизменяемой ссылке &self
        let current = self.count.get();
        self.count.set(current + 1);
    }
}

Это атомарно? Нет. Это работает только в одном потоке. Но для однопоточного кода (или внутри thread_local) это самая быстрая мутабельность, которая только возможна. #rust #std #optimization #interior_mutability 👉 @rust_lib

Rust
2 230
Почему Vec::new() это ловушка для производительности. 📈 Векторный рост: Избегаем реаллокаций Мы часто пишем:

let mut vec = Vec::new();
for item in heavy_iter {
    vec.push(item);
}

Что происходит под капотом? 1. Вектор создается пустым (0 байт). 2. Первый push: аллокация на 4 элемента (условно). 3. Пятый push: места нет. • Создается новый буфер (размером x2). • Все старые элементы копируются туда. • Старый буфер освобождается. • Новый элемент записывается. Это называется Reallocation. Это дорого. Если у вас 10 миллионов элементов, вы сделаете десятки реаллокаций и скопируете гигабайты данных просто так. Решение: Если вы хотя бы примерно знаете размер - подскажите компилятору.

// Идеально, если знаем точно
let mut vec = Vec::with_capacity(exact_count);

// Или используем итераторы, они часто сами знают свой размер
let vec: Vec<_> = heavy_iter.collect(); 

collect() умный. Он смотрит на size_hint итератора и сразу аллоцирует нужный буфер (если итератор "честный"). Правило: Vec::new() - только если вы правда не знаете, будет ли там хоть один элемент. В остальных случаях - with_capacity. #rust #performance #vectors 👉 @rust_lib