TL;DR
Rust の非同期ランタイム。イベント駆動でノンブロッキングな I/O の基盤で、ネットワークアプリケーションを書くための部品を提供する。
なぜ必要か
Rust の async/await は非同期のコードを書く構文だけを提供し、それを実行する仕組みは言語に含まれていない。Tokio はその実行役となるランタイムで、タスクのスケジューラや OS のイベントキューを使う I/O ドライバを持つ。axum は HTTP サーバの構築に必要な機能の一部を Tokio に任せている。
仕組み
公式ドキュメントによると、Tokio は主に次の部品からなる。
- ランタイム:
#[tokio::main]マクロで起動し、非同期のコードを実行する - スケジューラ: 少数のスレッドで多数のタスクを動かす。コアのスレッドはデフォルトで CPU コアごとに 1 つ作られる。タスクが切り替わるのは
.awaitの地点だけである - タスク:
tokio::spawnで作る軽量な実行単位。JoinHandleで結果を待てる - I/O、同期、時間: TCP や UDP、ファイル、チャネルや非同期の
Mutex、タイムアウトやスリープなどの API
注意点
公式のチュートリアルによると、Tokio は各タスクがほとんどの時間を I/O の待ちに使うアプリケーション向けに設計されている。CPU を使い切る並列計算には rayon を使うべきである。OS は一般に非同期のファイル API を持たないので、大量のファイルを読む処理では、普通のスレッドプールに比べて利点がない。リクエストを 1 回送るだけなら、ブロッキング版のライブラリを使うほうがプロジェクトは単純になる。