fa
Feedback
Rust

Rust

رفتن به کانال در Telegram

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

نمایش بیشتر
2 228
مشترکین
+324 ساعت
-17 روز
+630 روز
آرشیو پست ها
Rust
2 228
🚫 Убиваем 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 228
👣 Rust выбирают там, где цена ошибки — падение продакшена, утечки памяти и неконтролируемая многопоточность. Курс «Rust Developer. Professional» — следующий шаг после базового знакомства с Rust или работы на других языках. Вы разберёте Best Practices языка, асинхронность, архитектуру и многопоточность, научитесь использовать экосистему библиотек и писать отказоустойчивое, высокопроизводительное ПО. ❗️ Программа ориентирована на практику и инженерное мышление. Преподаватели — практикующие эксперты, работающие с системным и высоконагруженным ПО. Курс регулярно обновляется под реальные требования рынка. ▶️Старт курса 25 февраля. Курс доступен в рассрочку. Пройдите короткое вступительное тестирование и получите специальные условия на обучение: https://vk.cc/cUxQhX Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

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

Rust
2 228
🗝 Турбируем 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 228
⚡️ Забудь про 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 228
Почему 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

Rust
2 228
👣 Веб-приложения десятилетиями ассоциируются с JavaScript. Но сегодня у веба появляется альтернатива: Rust — быстрее, надёжнее и с предсказуемой моделью памяти. Это меняет подход к фронтенду и архитектуре веб-приложений. 🗓 3 февраля в 20:00 МСК приглашаем на открытый урок в преддверии старта курса «Rust Developer. Professional». На вебинаре покажем, как создавать веб-приложения на Rust: рассмотрим фреймворк Dioxus и альтернативы, разберём многокомпонентные SPA, рендер HTML и работу с HTTP-запросами. ❗️ Урок будет полезен Rust-разработчикам, которые хотят выйти за рамки серверного кода, и веб-разработчикам на JavaScript, ищущим более производительные и безопасные решения. 📣 Участие бесплатное, регистрация обязательна: https://vk.cc/cTXBj0 Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru

Rust
2 228
🤠 Трюк Индианы Джонса: std::mem::take Типичная ситуация: у вас есть &mut self, и вы хотите забрать поле (например, String или Vec), что-то с ним сделать, и, возможно, вернуть обратно или сохранить измененную версию. Компилятор бьет по рукам: нельзя просто так переместить (move) значение из-за мутабельной ссылки. Новички часто делают .clone(), чтобы успокоить borrow checker. Но это лишняя аллокация! Решение: std::mem::take. Оно забирает значение из ссылки, оставляя на его месте Default::default().

struct Buffer {
    data: Vec<u8>,
}

impl Buffer {
    fn process(&mut self) {
        // Мы "выкрадываем" вектор. 
        // В self.data теперь пустой Vec (без аллокаций).
        let raw_data = std::mem::take(&mut self.data);

        // Тяжелая обработка в другом потоке/функции, 
        // требующая владения (ownership)
        let processed = heavy_transform(raw_data);

        // Возвращаем результат
        self.data = processed;
    }
}

Это работает для всего, что реализует Default (Option, String, Vec). Для типов без Default есть std::mem::replace. Это zero-cost, семантически верно и намного быстрее клонирования. #rust #std #optimization #tips 👉 @rust_lib

Rust
2 228
🐮 Cow: Ленивое клонирование Все знают: лишний clone() - это грех. Но иногда нам нужно вернуть строку, которая может быть изменена, а может и нет. Допустим, мы чистим инпут от спецсимволов. 1. Если спецсимволов нет - зачем аллоцировать новую строку? Можно вернуть ссылку на исходную. 2. Если есть - придется создать новую String. Здесь на сцену выходит std::borrow::Cow (Clone on Write).

use std::borrow::Cow;

fn sanitize(input: &str) -> Cow<str> {
    if input.contains('!') {
        // Аллокация происходит только тут
        Cow::Owned(input.replace('!', "?")) 
    } else {
        // Тут мы просто возвращаем ссылку. Zero allocation.
        Cow::Borrowed(input) 
    }
}

Это мощнейший инструмент для хот-пасов (hot paths), где 90% данных не требуют изменений. Не ленитесь использовать Cow там, где можно избежать лишних аллокаций. #rust #performance #std 👉 @rust_lib

Rust
2 228
🛠 Cargo Expand: Загляни под капот макросам Признайтесь, у вас бывало такое: навесили #[derive(Serialize)] или сложный макрос из sqlx, получили странную ошибку компиляции и сидите в ступоре? Макросы это круто, но это черный ящик. Чтобы превратить его в прозрачный, поставьте cargo-expand.

cargo install cargo-expand

Запускаем:

cargo expand

И видите весь тот ужас (или красоту), который генерируется до того, как код попадет к компилятору. Это маст-хэв тулза при отладке async трейтов (привет, async-trait крейт) и понимании того, как работает "магия" фреймворков типа Actix или Rocket. P.S. Только не пугайтесь, когда увидите, во что разворачивается println!. #rust #tools #cargo #macro 👉 @rust_lib

Rust
2 228
👻 Сила пустоты: Zero-Sized Types (ZST) Мы часто говорим про "zero-cost abstractions", но редко задумываемся, как это выглядит в памяти. ZST - это типы, которые занимают 0 байт. Компилятор знает о них, но в рантайме они исчезают. Зачем это нужно, кроме экономии памяти? Для управления состоянием на уровне типов. Представьте, что у вас есть стейт-машина. Вместо того чтобы хранить enum State и делать проверки в рантайме:

struct Socket<State> {
    inner: FileDesc,
    _marker: PhantomData<State>, // 0 байт
}

// ZST-маркеры
struct Connected;
struct Disconnected;

impl Socket<Disconnected> {
    fn connect(self) -> Socket<Connected> {
        // Логика подключения...
        // Трансформация типа без оверхеда в памяти
        unsafe { std::mem::transmute(self) } 
    }
}

impl Socket<Connected> {
    fn send(&self, data: &[u8]) { ... }
}

В чем профит? 1. Вы физически не можете вызвать метод send у Disconnected сокета. Код просто не скомпилируется. 2. В скомпилированном бинарнике нет никаких флагов состояния, if state == connected и прочего мусора. Метод просто вызывается. Используйте систему типов, чтобы делать некорректные состояния невыразимыми (Make invalid states unrepresentable). #rust #advanced #architecture #zst 👉 @rust_lib

Rust
2 228
🦀 Error Handling: Библиотеки против Приложений Часто вижу в код-ревью кашу из способов обработки ошибок. Давайте раз и навсегда зафиксируем базу, чтобы ваш код был идиоматичным. Есть два лагеря, и вам нужно быть в обоих, но в разное время: 1. Вы пишите Библиотеку? Используйте thiserror. Почему: Вашим пользователям важно матчить ошибки. Им нужно знать, что именно пошло не так (NetworkError, ParseError), чтобы программно на это отреагировать. Вы не должны навязывать им тяжелые трейты.

#[derive(thiserror::Error, Debug)]
pub enum MyLibError {
    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),
    #[error("Invalid header")]
    InvalidHeader,
}

2. Вы пишите Приложение (CLI, Backend)? Используйте anyhow. Почему: Вам чаще всего плевать на тип ошибки в глубине стека, вам важно прокинуть её наверх (main), залоггировать контекст и упасть (или отдать 500-ку).

use anyhow::{Context, Result};

fn main() -> Result<()> {
    let config = std::fs::read_to_string("config.toml")
        .context("Не удалось прочитать конфиг")?;
    Ok(())
}

Итог: В библиотеках даем структуру (thiserror), в приложениях собираем контекст (anyhow). Не смешивайте. #rust #tips #error_handling 👉 @rust_lib

Rust
2 228
Добро пожаловать на «Полный курс Rust»! (2024) (Eng ver.) Этот обширный курс разработан, чтобы превратить вас из новичка в опытного программиста Rust, охватывая все основные темы, необходимые для создания надежного и эффективного программного обеспечения. В этом курсе вы начнете структурированный процесс обучения, который включает: Chapter 0 Introduction to Rust 00:00 Chapter 0 Install Rust 08:05 Chapter 0 Write first Rust program 09:26 Chapter 0 Cargo package manager 12:36 Chapter 1 Primitive Data Types 15:53 Chapter 2 Compound Data Types 25:12 Chapter 3 Functions 46:40 Chapter 4 Ownership 01:06:27 Chapter 5 Borrowing, and References 01:15:22 Chapter 6 Variables and Mutability 01:27:16 Chapter 7 Constants 01:31:05 Chapter 8 Shadowing 01:38:00 Chapter 9 Comments 01:46:49 Chapter 10 Introduction to Control Flow 01:49:33 Chapter 11 Looping Mechanisms 01:58:29 Chapter 12 Defining Structs 02:09:25 Chapter 13 Introduction to Enums 02:21:13 Chapter 14 Error Handling Techniques 02:33:07 Chapter 15 Collection Types 02:41:25 источник 👉 @rust_lib

Rust
2 228
OpenVMM — это проект Microsoft с открытым исходным кодом, который представляет собой модульный кросс-платформенный монитор виртуальных машин (VMM), написанный на языке Rust. 1. Ядро OpenHCL: В настоящее время OpenVMM является основным компонентом проекта OpenHCL (Open Hardware Compatibility Layer). Это так называемый «паравизор» (paravisor) — слой совместимости, который работает внутри контекста виртуальной машины, а не на хосте. 2. Зачем это нужно: Он используется в облаке Microsoft Azure для конфиденциальных вычислений. OpenVMM позволяет запускать обычные, немодифицированные операционные системы (Windows, Linux) в защищенных средах (например, на базе технологий Intel TDX или AMD SEV-SNP), эмулируя устройства и обеспечивая безопасность. 3. Безопасность и язык Rust: Проект написан на Rust для обеспечения безопасности памяти (memory safety), что критически важно для программного обеспечения уровня гипервизора во избежание уязвимостей. 4. Кросс-платформенность: Поддерживает архитектуры x86-64 и AArch64 (ARM64) и может работать поверх различных гипервизоров (Hyper-V, KVM, macOS Hypervisor.framework). По сути, это низкоуровневый системный инструмент, который позволяет Microsoft предоставлять современные функции безопасности и аппаратного ускорения в облаке Azure, сохраняя совместимость со старыми или стандартными образами операционных систем. https://github.com/microsoft/openvmm 👉 @rust_lib

Rust
2 228
Ghostport Высокопроизводительный инструмент для подмены портов, написанный на Rust. Сбивайте с толку порт-сканеры с помощью динамической эмуляции сервисов на всех портах. Поддерживает настраиваемые сигнатуры, эффективную асинхронную обработку и простое перенаправление трафика. Особенности - Динамическая эмуляция портов: отвечает на порт-сканирование набором правдоподобных сигнатур сервисов. - Настраиваемые сигнатуры: легко добавлять или изменять сигнатуры сервисов через простой текстовый файл. - Высокая производительность: построен на Rust и Tokio для эффективной асинхронной обработки соединений. - Гибкое логирование: режимы debug, verbose и quiet для разных сценариев использования. - Простота использования: простой интерфейс командной строки с разумными настройками по умолчанию. https://github.com/vxfemboy/ghostport 👉 @rust_lib

Rust
2 228
Пишем калькулятор на Rust с GUI Зачем еще один калькулятор? Да не зачем, просто как тестовый проект для рассмотрения GUI-библ
Пишем калькулятор на Rust с GUI Зачем еще один калькулятор? Да не зачем, просто как тестовый проект для рассмотрения GUI-библиотеки. Изначально я хотел попробовать такие крейты, как GPUI, Floem и Xilem, но первая, кажется, пока работает только под MacOS и Linux, вторая не позволяет установить иконку окну и кушает оперативы побольше Webview в Tauri, а до третьей я так и не добрался, узнав об Slint. Об Slint есть всего несколько новостных постов на Хабре, поэтому, возможно, вам будет интересно посмотреть, что это такое. https://habr.com/ru/articles/804655/ 👉 @rust_lib

Rust
2 228
Pico Pico - Embedded Programming with Rust В этой книге используется Raspberry Pi Pico 2 (на базе чипа RP2350), программируем
Pico Pico - Embedded Programming with Rust В этой книге используется Raspberry Pi Pico 2 (на базе чипа RP2350), программируемый на Rust. Рассмотрены разнообразные проекты - например, затухание светодиода, управление сервоприводом, измерение расстояния ультразвуковым датчиком, отображение изображения Ferris на OLED-дисплее, работа с RFID-ридером, проигрывание мелодий на зуммере, автоматическое включение светодиода при отсутствии света в комнате, измерение температуры и многое другое. https://pico.implrust.com/index.html 👉 @rust_lib

Rust
2 228
📕Создание приложения Movie Watchlist Manager на Angular: от компонентов до управления состоянием - разработчикам JavaScript/
📕Создание приложения Movie Watchlist Manager на Angular: от компонентов до управления состоянием - разработчикам JavaScript/TypeScript, Junior/Middle разработчикам, желающим освоить Angular, Frontend-разработчикам на других фреймворках (React, Vue) На открытом уроке 19 ноября в 20:00 мск мы погрузимся в созданию приложения по отслеживанию просмотренных фильмов/сериалов с использованием сигнальных сторов в Angular: 📗 На вебинаре разберем: 1. Создание компонентов и подключение API для поиска и добавления фильмов. 2. Организация архитектуры проекта и лучшие практики. 📘 В результате на практике изучите и освоите базовые концепции Angular (компоненты, сервисы, DI), работу с формами, API и реактивными потоками, использование store для управления состоянием приложения и лучшие методы построения современного SPA-приложения на Angular. 👉 Регистрация на урок и подробности о курсе Angular Developer: https://vk.cc/cRpDSs Все участники открытого урока получат скидку на курс "Angular Developer" Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576