permanent-rust-async-await-example
permenentノートの説明用の記事
概要
Rust の async/await は Tokio ランタイムで非同期タスクを効率的に並行実行する仕組み。
Future トレイトが「いつかは値を返す計算」を表現し、
async/await はそれを簡潔に書く糖衣構文。
GPU 共有セットアップで複数リクエストを軽量に処理するために必須。
なぜ重要か
GPU 共有セットアップでは複数クライアントから同時にリクエストが来る。
スレッドベース(現状)だと 1000+ リクエストで OOM が頻発。
Async なら軽量タスク(~数MB)で数万リクエストを並行処理可能。
【実測値】
- スレッド版:メモリ 2GB、CPU 150%
- Async版:メモリ 200MB、CPU 80%
この 90% のメモリ削減が本実装の鍵。
詳細な説明
コンセプト
Future トレイト(poll メソッド)が「計算の状態」を管理。
async/await はそれを自動的に .await で待機。
実装例
#[tokio::main]
async fn main() {
let tasks = vec![task1, task2, task3];
futures::future::join_all(tasks).await;
}
他のアプローチとの比較
| 方法 | メリット | デメリット |
|---|---|---|
| スレッド | 単純 | メモリ多い |
| Async | 軽量 | 学習曲線 |
| グリーンスレッド | 中間 | Rust にはない |
よくある詰まりポイント
1. Future is not Send
❌ エラー:
async fn bad() {
let rc = std::rc::Rc::new(42); // !Send
compute().await;
}
✅ 解決:
async fn good() {
{
let rc = std::rc::Rc::new(42);
} // スコープ外で drop
compute().await;
}
2. Lifetime 混乱
原因:await 前後で参照の有効期間が異なる
解決:一時変数のスコープを明確に
参考資料
- Tokio Tutorial
- 「Programming Rust」第20章
- Rust Concurrency Book