4 ポイント 投稿者 GN⁺ 2024-03-26 | 1件のコメント | WhatsAppで共有
  • Rust コミュニティでは、「スレッドは async/await でできることをすべて行え、しかもよりシンプルなのに、なぜ async/await を選ぶのか?」という疑問をよく目にする
  • Rust は低レベル言語であり、Coroutine の複雑さを隠さない。これは、プログラマーが非同期を意識しなくてもデフォルトで非同期になる Go のような言語とは対照的な考え方である
  • 賢いプログラマーは複雑さを避けようとするが、なぜ async/await が必要なのか?

背景を知る

  • Rust は低レベル言語である。コードは一般に線形的で、ある作業が終わると別の作業が実行される
  • Web サーバーのように、同時に多くの作業を実行しなければならない場合、線形コードでは問題が生じる
  • 初期の Web は、この問題を解決するためにスレッディングを導入しようとした
  • スレッドを使えば複数のクライアントを同時に処理できるが、プログラマーたちは並行性を OS 空間からユーザー空間へ持ち込みたいと考えてきた

タイムアウトの問題

  • Rust の最大の利点の 1 つは 合成可能性(composability) である
  • async/await は、この合成可能性を I/O バウンドな関数にも適用できるようにする
  • たとえば、クライアント処理関数にタイムアウトを追加したい場合、2 つのコンビネーターを使って実装できる

テーマ別スレッド

  • スレッドを使った例でタイムアウトを実装するのは簡単ではない
  • TcpStream には set_read_timeoutset_write_timeout 関数があるが、その使い方には制約がある
  • Rust のコンビネーターを使ってタイムアウトをプログラミングする方法も示されているが、これは TcpStream に限られ、追加のシステムコールも必要になる

Async の成功事例

  • HTTP エコシステムは、主要なランタイム機構として async/await を採用している
  • towerasync/await の強力さを示す例であり、タイムアウト、レート制限、ロードバランシングなどを提供する
  • macroquad は Rust のゲームエンジンで、async/await を使ってエンジンを実行している

Async のイメージ改善

  • async の利点は広く知られておらず、一部の人には誤解されることがある
  • Rust コミュニティは、async Rust の性能上の利点を過大評価し、意味のある利点を過小評価する傾向がある
  • async/await は、同期 Rust では数十のスレッドやチャネルなしには表現できないパターンを簡潔に表現できる、強力なプログラミングモデルとして捉えるべきである

GN⁺ の意見

  • async/await は並行性を扱う際にコードの複雑さを増す一方で、非常に多くのクライアントを効率的に処理する能力を提供する
  • この記事は、async/await が単なる性能上の利点を超えて、プログラミングモデルとしての強みを持つことを強調している
  • Rust の async/await は、さまざまな I/O 処理に対する合成可能性を提供し、これは特にネットワークサービスや Web サーバーのような分野で有用である
  • 批判的な視点で見ると、async/await の複雑さは初心者開発者にとって参入障壁となり得るため、それを乗り越えるための教育的な取り組みが必要である
  • 同様の機能を提供する別のプロジェクトとしては、Node.js の async/await 実装や Python の asyncio ライブラリがあり、これらも似たパラダイムを提供している
  • async/await を導入する際には、コードの複雑さと保守性を考慮する必要があるが、同時に多数のクライアントを処理しなければならない場合には、このモデルが大きな利点をもたらす

1件のコメント

 
GN⁺ 2024-03-26
Hacker Newsの意見
  • async/await とシングルスレッド

    • JavaScript のモデルのように、シングルスレッド上での async/await は単純で、よく理解されている。
    • スレッドを使えば複数の CPU で問題を処理でき、Rust はロック管理を助けてくれる。
    • 異なる優先度のスレッドを持つことができ、計算に制約がある場合には必要になる。
    • マルチスレッドの async/await は複雑である。計算に制約があるセクションではモデルが崩壊しうる。
    • Rust ではマルチスレッド計算はうまく機能しない。問題点としては以下がある。
      • futex の競合崩壊: 一部のストレージアロケータで問題になりうる。
      • 不公平な mutex による飢餓: 標準の Mutex と crossbeam-channel のチャネルは不公平である。
  • async/await 対スレッド

    • 批判は複雑さに関するものではなく、選択によってエコシステムが分裂し、一方が劣ったものになることに向けられている。
    • Rust エコシステムは、I/O 作業をするには全面的に async/await を使わなければならないと決めた。
    • Rust が async/await 以外のものを、より組み合わせ可能な抽象化にしていれば不満は消えていただろう。
  • 記事に対する問題点

    • Web サーバーの例が 1 つ示されただけで、スレッドについて誤った形で解決されている。
    • プログラマは OS スレッドではなく、概念的・意味的なスレッドを求めている。
    • OS スレッドは高コストであり、私たちは軽量なスレッドを求めている。
    • Web サーバーの例でのタイムアウト実装にも問題がある。
  • 触れられていない点

    • async/await はシングルスレッドで実行されるため、ロックや同期が不要である。
    • async/await におけるエラー伝播は明確ではない。
    • ネットワーク I/O におけるバックプレッシャーにも言及されるべきである。
  • キャンセルに関する重要な点

    • 将来のどのタスクでも簡単にキャンセルできる。
    • スレッドにおけるキャンセルは複雑で、強制的なスレッド停止は信頼できない。
    • Rust の async モデルでは、すべての future に外部からタイムアウトを追加できる。
  • async/await に対するマーケティングのようなキャンペーン

    • async/await は技術的な失敗であり、コミュニティに大きなコストをもたらした。
    • Rust は依然として最高の言語だが、この論争が永遠に続くのではないかと心配している。
  • async/await 対ファイバー

    • Rust は以前グリーンスレッドを持っていたが、意図的に削除された。
    • future をいつでも drop できる能力には大きなコストが伴う。
    • async/await の組み合わせ可能性を称賛するのは奇妙である。
  • Rust における async/await の主な利点

    • スレッドや動的メモリがない状況でも動作できる。
    • 並行性を利用してコードを簡潔に書ける。
  • async/await に関する誤解

    • シングルスレッドにおける並行性メカニズムがなぜ必要なのか理解していない人がいる。
    • UI プログラミング、GPU との通信、ランタイム間通信などで async/await は有用である。
  • async/await をスレッドより選ぶ理由

    • async/await はクライアント/リクエスト/タスク状態のメモリ使用量を減らせる。
    • 状態圧縮は、メモリ速度が遅い現代において性能上重要である。
    • async/await と CPS は、クライアントごとのメモリ使用量を減らすのに効果的である。