Rust
2.24K subscribers
173 photos
109 videos
2 files
258 links
Полезный контент по программированию на Rust
Download Telegram
🦀 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

📲 Мы в MAX

👉 @rust_lib
👍5🔥5👎3❤2
This media is not supported in your browser
VIEW IN TELEGRAM
Pake

🤱🏻 Превратите любую веб-страницу в настольное приложение с помощью Rust.

Pake поддерживает Mac, Windows и Linux.

https://github.com/tw93/Pake

📲 Мы в MAX

👉 @rust_lib
👍6🔥5❤3
🚀 Подборка полезных 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 и др.
https://max.ru/tipsysdmin Типичный Сисадмин
https://max.ru/channel_win_sysadmin Системный Администратор Windows
https://max.ru/channel_linux_admin Linux: Системный администратор
https://max.ru/channel_linuxmod Linux
https://max.ru/channel_i_linux Системный администратор
https://max.ru/channel_devopslib DevOps, SRE, Sysadmin
https://max.ru/channel_devops_star DevOps Star (Звезда Девопса)

Excel лайфхак 📌
https://t.iss.one/Excel_lifehack Excel лайфхак

Английский с нуля 🇬🇧
https://max.ru/UchuEnglish

1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://max.ru/channel_DevLab1C 1С:Предприятие 8

Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
https://max.ru/channel_cpp_geek C++ geek

Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика

Программирование React📌
https://max.ru/react_lib React

Программирование Rust📌
https://max.ru/channel_rust_lib

Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика

Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
https://max.ru/channel_java_geek Java Geek

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 Обучающие видео, книги по Физике и Математике

Вакансии в IT📌
https://max.ru/progjob
https://max.ru/channel_rabotait

Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных

Городские📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
https://max.ru/channel_krasnodar_novosty Краснодар Новости
https://max.ru/channel_novosibirsk_novosti Новосибирск
https://max.ru/channel_samara_novosti Новости Самары
https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга
https://max.ru/channel_kazan_novosti Новости Казани
https://max.ru/channel_omsk_novosti Новости Омска
https://max.ru/channel_moskva_24 Москва 24
💩13🤮11👎4👍1🍌1
👻 Сила пустоты: 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

📲 Мы в MAX

👉 @rust_lib
❤10👍1
🛠 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

📲 Мы в MAX

👉 @rust_lib
👍7🔥4😁2
Владение, заимствование и ссылки в Rust: как компилятор делает ваш код безопасным

В Rust одна из самых непривычных для разработчиков тем — это ownership (владение) и borrowing (заимствование). Многие пытаются писать на Rust как на C++ или Python, натыкаются на компилятор, и правила borrow checker'а поначалу кажутся слишком строгими. На деле компилятор просто защищает вас от ошибок, которые в других языках приводят к падениям, утечкам памяти и гонкам данных. Но чтобы подружиться с borrow checker’ом, нужно понять логику, а не заучивать правила.

На открытом вебинаре 9 сентября в 20:00 разберём фундаментальные концепции Rust, которые делают код безопасным без сборщика мусора. Поговорим о том, почему на одни и те же данные можно взять сколько угодно иммутабельных ссылок (&), но мутабельная (&mut) может быть только одна — и не одновременно с иммутабельными. Разберём, чем перемещение (move) отличается от копирования (Copy/Clone). Обсудим, что такое время жизни (lifetimes): когда его нужно указывать явно, а когда компилятор выводит его сам по правилам элизии (lifetime elision). На практических примерах посмотрим, как разбирать типичные ошибки borrow checker'а, писать функции, безопасно работающие со ссылками и слайсами, и почему правила владения и заимствования предотвращают гонки данных, обращение к освобождённой памяти и двойное освобождение.

Вебинар не для тех, кто хочет просто «посмотреть синтаксис» без погружения в модель памяти. Подойдёт тем, кто уже знаком с основами языка — переменными, функциями, типами — и хочет наконец разобраться в модели памяти Rust, а также программистам с опытом в C++, Java или Python, которые хотят понять самую важную и необычную концепцию языка.

👉 Записаться: https://vk.cc/d1fh5M

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
👍2❤1
🐮 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

📲 Мы в MAX

👉 @rust_lib
👍10🔥3❤2
🤠 Трюк Индианы Джонса: 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

📲 Мы в MAX

👉 @rust_lib
❤9👍5🔥3
Почему 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

📲 Мы в MAX

👉 @rust_lib
👍8🔥2❤1
Создание кроссплатформенного приложения с GUI на Rust: От идеи до реальности

Electron-приложения тяжелые, потребляют много памяти, а на Rust можно собрать легкое, быстрое и безопасное десктоп-приложение, которое будет работать на Windows, macOS и Linux. Tauri — это фреймворк, который позволяет использовать веб-технологии (HTML/CSS/JS) для интерфейса и мощь Rust для бэкенда. Но чтобы собрать работающий продукт, а не просто «посмотреть пример», нужно понимать, как связать фронтенд с бэкендом, работать с файловой системой, делать асинхронные вызовы и правильно собирать билды.

На открытом вебинаре 23 сентября в 20:00 разберём полный цикл создания кроссплатформенного GUI-приложения на Rust с использованием Tauri. Посмотрим, как организовать проект, как писать логику на Rust и подключать её к интерфейсу, как сохранять и загружать данные,безопасно работать с файловой системой и системными вызовами через новую систему разрешений (permissions) и возможностей (capabilities) в Tauri 2, а также выполнять долгие операции асинхронно. Отдельно обсудим сборку готового приложения, отладку с помощью встроенных инструментов Tauri и лучшие практики, которые помогут избежать типичных ошибок.

Вебинар не для тех, кто ждёт готового шаблона «скопируй-вставь» без понимания архитектуры. Идеально подойдёт фронтенд-разработчикам, которые хотят создавать настоящие десктоп-приложения, программистам на других языках, интересующимся Rust и кроссплатформенной разработкой, а также энтузиастам, которые устали от тяжелых Electron-приложений.

После вебинара вы сможете создавать функциональные десктоп-приложения на Rust с красивым интерфейсом, разрабатывать логику на бэкенде и связывать её с UI, грамотно настраивать политики безопасности доступа к ресурсам ОС, а также собирать и распространять готовое приложение пользователям.

👉 Записаться: https://vk.cc/d1KKyw

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
🥱2
⚡️ Забудь про 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

📲 Мы в MAX

👉 @rust_lib
👍6❤4🔥2
🗝 Турбируем 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

📲 Мы в MAX

👉 @rust_lib
👍9🔥3⚡1
🔮 Ты не пройдешь: Магия предсказателя ветвлений

Вы когда-нибудь задумывались, почему обработка отсортированного массива чисел происходит в разы быстрее, чем случайного, даже если логика одна и та же?

Всё дело в конвейере (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

📲 Мы в MAX

👉 @rust_lib
👍3❤2🔥1🤝1
🥶 Холодный расчет: #[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

📲 Мы в MAX

👉 @rust_lib
👍9🔥5
🚫 Убиваем 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

📲 Мы в MAX

👉 @rust_lib
❤8👍4🔥2
🏎️ 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

📲 Мы в MAX

👉 @rust_lib
🤝3❤2
💀 Хардкорный режим: 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

📲 Мы в MAX

👉 @rust_lib
❤6👍1
🚀 Подборка полезных 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 и др.
https://max.ru/tipsysdmin Типичный Сисадмин
https://max.ru/channel_win_sysadmin Системный Администратор Windows
https://max.ru/channel_linux_admin Linux: Системный администратор
https://max.ru/channel_linuxmod Linux
https://max.ru/channel_i_linux Системный администратор
https://max.ru/channel_devopslib DevOps, SRE, Sysadmin
https://max.ru/channel_devops_star DevOps Star (Звезда Девопса)

Excel лайфхак 📌
https://t.iss.one/Excel_lifehack Excel лайфхак

Английский с нуля 🇬🇧
https://max.ru/UchuEnglish

1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
https://max.ru/channel_DevLab1C 1С:Предприятие 8

Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
https://max.ru/channel_cpp_geek C++ geek

Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика

Программирование React📌
https://max.ru/react_lib React

Программирование Rust📌
https://max.ru/channel_rust_lib

Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика

Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
https://max.ru/channel_java_geek Java Geek

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 Обучающие видео, книги по Физике и Математике

Вакансии в IT📌
https://max.ru/progjob
https://max.ru/channel_rabotait

Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных

Городские📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
https://max.ru/piterspb Питер Новости: Санкт-Петербург / СПБ / ДТП
https://max.ru/channel_krasnodar_novosty Краснодар Новости
https://max.ru/channel_novosibirsk_novosti Новосибирск
https://max.ru/channel_samara_novosti Новости Самары
https://max.ru/channel_ekaterinburg_novosti Новости Екатеринбурга
https://max.ru/channel_kazan_novosti Новости Казани
https://max.ru/channel_omsk_novosti Новости Омска
https://max.ru/channel_moskva_24 Москва 24
💩7👍1👎1🤡1🖕1
🚀 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

📲 Мы в MAX

👉 @rust_lib
🔥6👍4
🪄 Разрушаем магию: Твоя 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

📲 Мы в MAX

👉 @rust_lib
🔥5👍4