非同期Rustの現状
async Rustの一部は、同期Rustと同じ安定性保証でサポートされています。 その他の部分はまだ成熟途上であり、時間とともに変化していきます。 async Rustでは、次のことを期待できます。
- 典型的な並行ワークロードに対する卓越したランタイム性能。
- ライフタイムやピン留めなど、高度な言語機能とのより頻繁な関わり。
- 同期コードと非同期コードの間、および異なる非同期ランタイム間の いくつかの互換性上の制約。
- 非同期ランタイムと言語サポートが継続的に進化していることによる、 より高いメンテナンス負担。
要するに、async Rustは同期Rustよりも使うのが難しく、 メンテナンス負担が高くなる可能性がありますが、 その見返りとしてクラス最高の性能を得られます。 async Rustのあらゆる領域は絶えず改善されているため、 これらの問題の影響は時間とともに薄れていくでしょう。
言語とライブラリのサポート
非同期プログラミングはRust自体によってサポートされていますが、 ほとんどの非同期アプリケーションは、 コミュニティクレートが提供する機能に依存しています。 そのため、言語機能とライブラリサポートの組み合わせに 頼る必要があります。
Futureトレイトのような、 最も基本的なトレイト、型、関数は標準ライブラリによって提供されています。async/await構文はRustコンパイラによって直接サポートされています。- 多くのユーティリティ型、マクロ、関数は
futuresクレートによって提供されています。これらは任意のasync Rustアプリケーションで使用できます。 - 非同期コードの実行、IO、タスクの生成は、Tokioやasync-stdなどの 「非同期ランタイム」によって提供されています。ほとんどの非同期アプリケーションと一部の 非同期クレートは、特定のランタイムに依存しています。詳細については “非同期エコシステム”セクションを参照してください。
同期Rustで慣れているかもしれない一部の言語機能は、まだ async Rustでは利用できません。特に、Rustでは1.75.0 stableまでトレイト内でasync 関数を宣言できませんでした(そして、それらのトレイトに対する動的ディスパッチには今も制限があります)。代わりに、同じ 結果を得るには回避策を使う必要があり、それにより記述が冗長になる場合があります。
コンパイルとデバッグ
ほとんどの場合、async Rustにおけるコンパイラエラーとランタイムエラーは、 Rustでこれまで常にそうであったのと同じように機能します。いくつかの 注目すべき違いがあります。
コンパイルエラー
async Rustのコンパイルエラーは、同期Rustと同じ高い標準に準拠していますが、 async Rustはライフタイムやピン留めなど、より複雑な言語機能に依存することが多いため、 この種のエラーにより頻繁に遭遇する可能性があります。
ランタイムエラー
コンパイラがasync関数に遭遇するたびに、内部でステートマシンを生成します。 async Rustのスタックトレースには通常、これらのステートマシンからの詳細と、 ランタイムからの関数呼び出しが含まれます。そのため、スタックトレースの解釈は、 同期Rustの場合よりも少し複雑になることがあります。
新しい失敗モード
async Rustでは、いくつかの新しい失敗モードが起こり得ます。たとえば、
非同期コンテキストからブロッキング関数を呼び出した場合や、
Futureトレイトを誤って実装した場合です。このようなエラーは、コンパイラと、
場合によってはユニットテストさえも静かに通過してしまうことがあります。
この本が提供することを目指している基礎概念をしっかり理解しておくことで、
これらの落とし穴を避けるのに役立ちます。
互換性に関する考慮事項
非同期コードと同期コードは、常に自由に組み合わせられるわけではありません。 たとえば、同期関数からasync関数を直接呼び出すことはできません。 同期コードと非同期コードはまた、異なる設計パターンを促進する傾向があり、 異なる環境向けのコードを組み合わせるのが難しくなることがあります。
非同期コード同士でさえ、常に自由に組み合わせられるわけではありません。一部のクレートは、 機能するために特定の非同期ランタイムに依存しています。その場合、通常は クレートの依存関係リストに指定されています。
これらの互換性の問題は選択肢を制限する可能性があるため、 必要になる可能性のある非同期ランタイムとクレートを早い段階で調査するようにしてください。 いったんランタイムを決めて落ち着けば、互換性について あまり心配する必要はなくなります。
性能特性
async Rustの性能は、使用している非同期ランタイムの 実装に依存します。 async Rustアプリケーションを支えるランタイムは比較的新しいものの、 ほとんどの実用的なワークロードで非常に優れた性能を発揮します。
とはいえ、非同期エコシステムの大部分は_マルチスレッド_ランタイムを前提としています。 そのため、単一スレッドの非同期アプリケーションが持つ理論上の性能上の利点、 つまりより低コストな同期処理を享受することが難しくなっています。 もう1つ見過ごされがちなユースケースは、ドライバーやGUIアプリケーションなどにとって 重要な_レイテンシに敏感なタスク_です。このようなタスクは、適切にスケジュールされるために ランタイムやOSのサポートに依存します。 将来的には、これらのユースケースに対するライブラリサポートの向上が期待できます。