# async в Rust и Tokio

> Асинхронное программирование в Rust на основе async/await и ленивых футур, которые исполняет внешняя среда выполнения; Tokio — самая распространённая такая среда для сетевых приложений.

Источник: https://llmdocs.ru/wiki/rust-async-tokio/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0

- **async/await**: стабилизированы в Rust 1.39 (ноябрь 2019)
- **Модель**: ленивые футуры с опросом (poll), без встроенной среды выполнения
- **Tokio**: с 2016, версия 1.0 — декабрь 2020
- **Автор Tokio**: Карл Лерхе и сообщество
- **Лицензия Tokio**: MIT
- **Экосистема**: hyper, axum, reqwest, tonic, sqlx
- **Альтернативы**: smol, embassy (встраиваемые системы)
**Асинхронное программирование в Rust** позволяет одному потоку обслуживать тысячи одновременных операций ввода-вывода — сетевых соединений, запросов к базе данных, таймеров, — не создавая отдельный поток операционной системы на каждую. Функция, объявленная как `async fn`, возвращает **футуру** (*future*) — значение, представляющее ещё не завершённое вычисление, а `.await` ждёт её результата, не блокируя поток. В отличие от многих языков, в [Rust](https://llmdocs.ru/wiki/rust.md) нет встроенной среды выполнения: футуры исполняет подключаемая библиотека, и самая распространённая из них — **Tokio**.

На асинхронном Rust построены веб-серверы, прокси, базы данных, брокеры сообщений и клиентские SDK облачных сервисов.

## История

Синтаксис `async`/`await` стабилизировали в Rust 1.39 в ноябре 2019 года после нескольких лет проектирования.[3] Ключевое решение — **футуры с нулевой стоимостью**: компилятор превращает асинхронную функцию в конечный автомат, размер и поведение которого известны при компиляции, без выделения памяти в куче на каждый шаг. Tokio начали развивать в 2016 году; версия 1.0 с гарантией стабильности API вышла в декабре 2020 года.[4] В Rust 1.75 (2023) появились асинхронные методы в трейтах (см. [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md)).

## Как работают футуры

Футура реализует трейт `Future` с методом `poll`. Среда выполнения опрашивает футуру: та либо возвращает `Ready(результат)`, либо `Pending` и регистрирует **пробуждатель** (*waker*), который сообщит среде, когда стоит опросить её снова — например, когда в сокет пришли данные.[5]

Главное отличие от JavaScript и [asyncio](https://llmdocs.ru/wiki/asyncio.md) в Python: футуры в Rust **ленивые**. Вызов `async fn` ничего не выполняет, пока футуру не начнут ожидать через `.await` или не передадут исполнителю. Забытая без `.await` футура просто не выполнится — компилятор предупредит об этом.

## Пример с Tokio

```toml
# Cargo.toml
[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = "0.12"
```

```rust
use std::time::Duration;
use tokio::time::sleep;

async fn fetch(url: &str) -> Result<usize, reqwest::Error> {
    let body = reqwest::get(url).await?.text().await?;
    Ok(body.len())
}

#[tokio::main]                                       // запускает многопоточную среду выполнения
async fn main() {
    let urls = ["https://example.com", "https://www.rust-lang.org"];

    // конкурентно: обе загрузки идут одновременно
    let handles: Vec<_> = urls.iter()
        .map(|u| tokio::spawn(fetch(u)))             // отдельная задача на каждый URL
        .collect();
    for h in handles {
        println!("{:?}", h.await.unwrap());
    }

    // таймаут и выбор первого завершившегося
    tokio::select! {
        r = fetch("https://example.com") => println!("ответ: {r:?}"),
        _ = sleep(Duration::from_secs(2)) => println!("таймаут"),
    }
}
```

## Что даёт Tokio

| Компонент | Назначение |
|---|---|
| Планировщик | многопоточный исполнитель с перехватом задач (*work stealing*) |
| Ввод-вывод | асинхронные TCP, UDP, Unix-сокеты, файлы, процессы |
| Время | `sleep`, `timeout`, `interval` |
| Синхронизация | асинхронные `Mutex`, `RwLock`, `Semaphore`, каналы `mpsc`, `oneshot`, `broadcast`, `watch` |
| Задачи | `tokio::spawn`, `JoinSet`, отмена через удаление футуры |

Подробное введение — в официальном руководстве Tokio, где по шагам строится мини-версия [Redis](https://llmdocs.ru/wiki/redis.md).[2]

## Экосистема

- **hyper** — низкоуровневая реализация [HTTP](https://llmdocs.ru/wiki/http.md)/1 и HTTP/2; **axum** — популярный веб-фреймворк поверх hyper и Tokio.[6]
- **reqwest** — HTTP-клиент, **tonic** — gRPC, **sqlx** — асинхронный доступ к [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), MySQL и SQLite.
- **tower** — промежуточные слои: повторы, таймауты, ограничение нагрузки.
- **tracing** — структурированное логирование и трассировка асинхронного кода.

## Подводные камни

- **Блокирующий код в асинхронной задаче.** Тяжёлые вычисления или синхронный ввод-вывод внутри `async fn` останавливают поток исполнителя и все задачи на нём. Для них есть `tokio::task::spawn_blocking`.
- **Требование `Send`.** Задачи многопоточного исполнителя могут переезжать между потоками, поэтому всё, что живёт через `.await`, должно быть `Send`. Типичная ошибка — держать `std::sync::MutexGuard` или `Rc` через точку ожидания.
- **«Цветные» функции.** Асинхронную функцию нельзя просто вызвать из синхронной — нужно запустить среду выполнения. Библиотеки нередко предлагают обе версии API.
- **Отмена.** Удаление футуры отменяет её в ближайшей точке `.await`, поэтому код между точками ожидания должен оставлять данные в согласованном состоянии.
- **Сложность.** Ошибки компиляции с `Pin`, временами жизни и `Send` — самая трудная часть изучения асинхронного Rust; подробности — в официальной книге по асинхронному программированию.[1]

## Когда нужен async

Асинхронность оправдана для программ с большим числом одновременных операций ввода-вывода: серверов, прокси, краулеров (см. [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md)). Для вычислений лучше подходят потоки и библиотеки вроде rayon, а для простых утилит командной строки — обычный синхронный код. Сравнение с моделью [горутин](https://llmdocs.ru/wiki/goroutines-channels.md) Go: там планировщик встроен в язык, а в Rust среда выполнения выбирается и подключается явно.

## См. также

- [Rust (язык)](https://llmdocs.ru/wiki/rust.md)
- [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md)
- [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md)
- [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md)
- [asyncio](https://llmdocs.ru/wiki/asyncio.md)

## Источники

1. [Asynchronous Programming in Rust (async book)](https://rust-lang.github.io/async-book/)
2. [Tokio — Tutorial](https://tokio.rs/tokio/tutorial)
3. [Rust Blog — Async-await on stable Rust! (1.39)](https://blog.rust-lang.org/2019/11/07/Async-await-stable.html)
4. [Tokio Blog — Announcing Tokio 1.0](https://tokio.rs/blog/2020-12-tokio-1-0)
5. [Rust std — Trait std::future::Future](https://doc.rust-lang.org/std/future/trait.Future.html)
6. [axum — docs.rs](https://docs.rs/axum)
