Rust
2.23K subscribers
169 photos
106 videos
2 files
233 links
Полезный контент по программированию на Rust
Download Telegram
🪄 Разрушаем магию: Твоя 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
👍2073🥰1🤗1
Хватит дергать: 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
👍12🔥42🥰2👨‍💻1🤗1