Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Итоги и справочная карточка

Краткая справочная карточка

Ментальная модель async

┌─────────────────────────────────────────────────────┐
│  async fn → конечный автомат (enum) → impl Future   │
│  .await   → poll() вложенного future                │
│  исполнитель → loop { poll(); спать_до_пробуждения; }│
│  waker    → «эй, исполнитель, опроси меня снова»    │
│  Pin      → «обещаю, что не переместят в памяти»    │
└─────────────────────────────────────────────────────┘

Шпаргалка по частым паттернам

ЗадачаРешение
Запустить два future одновременноtokio::join!(a, b)
Состязать два futuretokio::select! { ... }
Запустить фоновую задачуtokio::spawn(async { ... })
Выполнить блокирующий код в asynctokio::task::spawn_blocking(|| { ... })
Ограничить конкурентностьSemaphore::new(N)
Собрать результаты многих задачJoinSet
Делить состояние между задачамиArc<Mutex<T>> или каналы
Graceful shutdownwatch::channel + select!
Обрабатывать поток по N элементов.buffer_unordered(N)
Установить таймаут на futuretokio::time::timeout(dur, fut)
Повтор с задержкойСобственный комбинатор (см. гл. 13)

Краткая справка по закреплению (pinning)

СитуацияЧто использовать
Закрепить future в кучеBox::pin(fut)
Закрепить future на стекеtokio::pin!(fut)
Закрепить тип UnpinPin::new(&mut val) — безопасно и бесплатно
Вернуть закреплённый трейт-объект-> Pin<Box<dyn Future<Output = T> + Send>>

Выбор канала

КаналОтправителиПолучателиЗначенияКогда использовать
mpscN1ПотокОчереди задач, шины событий
oneshot11ОдноЗапрос/ответ, уведомление о завершении
broadcastNNВсе получают всёРассылка уведомлений, сигналы остановки
watch1NТолько последнееОбновления конфигурации, статус здоровья

Выбор мьютекса

МьютексКогда использовать
std::sync::MutexБлокировка удерживается недолго, никогда через .await
tokio::sync::MutexБлокировку нужно удерживать через .await
parking_lot::MutexВысокая конкуренция, без .await, нужна производительность
tokio::sync::RwLockМного читателей, мало писателей, блокировки пересекают .await

Краткая справка по решениям

Нужна конкурентность?
├── Ограничена I/O → async/await
├── Ограничена CPU → rayon / std::thread
└── Смешанная → spawn_blocking для CPU-части

Выбор рантайма?
├── Серверное приложение → tokio
├── Библиотека → не привязана к рантайму (крейт futures)
├── Встраиваемая система → embassy
└── Минимальный → smol

Нужны конкурентные future?
├── Могут быть 'static + Send → tokio::spawn
├── Могут быть 'static + !Send → LocalSet
├── Не могут быть 'static → FuturesUnordered
└── Нужно отслеживать/прерывать → JoinSet

Частые сообщения об ошибках и их исправление

ОшибкаПричинаИсправление
future is not SendТип !Send удерживается через .awaitОграничьте область видимости значения, чтобы оно уничтожалось до .await, или используйте рантайм current_thread
borrowed value does not live long enough в spawntokio::spawn требует 'staticИспользуйте Arc, clone() или FuturesUnordered
the trait Future is not implemented for ()Пропущен .awaitДобавьте .await к асинхронному вызову
cannot borrow as mutable в pollСамоссылающееся заимствованиеПравильно используйте Pin<&mut Self> (см. гл. 4)
Программа молча зависаетЗабыли вызвать waker.wake()Убедитесь, что каждый путь с Pending регистрирует waker и вызывает его

Дополнительная литература

РесурсЗачем
Tokio TutorialОфициальное практическое руководство — отлично для первых проектов
Async Book (официальная)Рассказывает о Future, Pin, Stream на уровне языка
Jon Gjengset — Crust of Rust: async/awaitДвухчасовой глубокий разбор внутреннего устройства с живым кодом
Alice Ryhl — Actors with TokioАрхитектурный паттерн для продакшен-сервисов с состоянием
Without Boats — Pin, Unpin, and why Rust needs themИсходная мотивация от автора языка
Tokio mini-RedisПолный асинхронный проект на Rust — учебный код продакшен-качества
Документация TowerАрхитектура middleware/сервисов, которую используют axum, tonic, hyper

Конец руководства по асинхронному Rust