┌─────────────────────────────────────────────────────┐
│ async fn → конечный автомат (enum) → impl Future │
│ .await → poll() вложенного future │
│ исполнитель → loop { poll(); спать_до_пробуждения; }│
│ waker → «эй, исполнитель, опроси меня снова» │
│ Pin → «обещаю, что не переместят в памяти» │
└─────────────────────────────────────────────────────┘
Задача Решение
Запустить два future одновременно tokio::join!(a, b)
Состязать два future tokio::select! { ... }
Запустить фоновую задачу tokio::spawn(async { ... })
Выполнить блокирующий код в async tokio::task::spawn_blocking(|| { ... })
Ограничить конкурентность Semaphore::new(N)
Собрать результаты многих задач JoinSet
Делить состояние между задачами Arc<Mutex<T>> или каналы
Graceful shutdown watch::channel + select!
Обрабатывать поток по N элементов .buffer_unordered(N)
Установить таймаут на future tokio::time::timeout(dur, fut)
Повтор с задержкой Собственный комбинатор (см. гл. 13)
Ситуация Что использовать
Закрепить future в куче Box::pin(fut)
Закрепить future на стеке tokio::pin!(fut)
Закрепить тип Unpin Pin::new(&mut val) — безопасно и бесплатно
Вернуть закреплённый трейт-объект -> Pin<Box<dyn Future<Output = T> + Send>>
Канал Отправители Получатели Значения Когда использовать
mpscN 1 Поток Очереди задач, шины событий
oneshot1 1 Одно Запрос/ответ, уведомление о завершении
broadcastN N Все получают всё Рассылка уведомлений, сигналы остановки
watch1 N Только последнее Обновления конфигурации, статус здоровья
Мьютекс Когда использовать
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 и вызывает его
Конец руководства по асинхронному Rust