2 ポイント 投稿者 GN⁺ 2024-04-15 | 1件のコメント | WhatsAppで共有

WebAssemblyの限界とTree-shakingの重要性

  • WebAssemblyは多くの関心と期待にもかかわらず、Webでは限定的な成功しか収めていない

    • Photoshopのような成功事例もあるが、全体的にはWebAssemblyを活用したプロジェクトは多くない
    • 特にDOMを多用するアプリではWebAssemblyは適していない
    • JavaScriptとWebAssemblyのプログラミングモデルの違いが主な原因のひとつ
  • WebAssemblyはCやRustのような言語以外では大きく成功していない

    • C#のような言語はガベージコレクタなどのランタイムを一緒に提供しなければならない不便さがある
    • ただし参照型とガベージコレクションをサポートするWebAssemblyの新機能がまもなく導入される予定で、状況の改善が期待される

コンパイラのコード最適化能力がWebAssembly成功の鍵

  • WebAssemblyがWebで成功するには、コンパイラが小さく効率的なコードを生成できなければならない

    • 数キロバイト程度の小さなファイルサイズを維持することが重要
    • そうでなければ、誇大宣伝や特定のユーザーベースに依存せざるを得ない
  • JavaScriptの世界では、バンドラなどを通じてコードサイズ最適化が行われている

    • Tree-shakingは、プログラムで実際に使用される関数とデータ型だけを含める手法
  • Tree-shakingは、園芸学的にもアルゴリズム的にも不適切な比喩ではあるが、広く使われている用語

他の言語におけるTree-shakingの現状

  • GoやPythonなどランタイムが重い言語では、まだTree-shakingが最適化されていない

    • 最も単純なGoプログラムでも、WebAssemblyにコンパイルすると2MB以上のサイズになる
    • PythonのPyodideも約20MBのファイルをダウンロードしなければならない
  • サーバー環境ではバイナリサイズが大きな問題にならないため

    • モバイルなど制約のある環境向けには、MicroPython、TinyGoなどの軽量化されたツールチェーンが別途開発されることもある
  • Web環境向けの言語実装は既存のものと違わざるを得ない

    • DOMと相互作用すること自体が特異な環境だから
    • ClojureScriptは、Clojureとの違いを別途文書化している

Tree-shakingアルゴリズムに関する議論

  • 著者が開発中のHoot Schemeコンパイラは、現在およそ70KBのWasmコードを生成している

    • 関数(プロシージャ)定義だけを含めるのは比較的容易
    • しかし、以下のようないくつかの難しい点がある
  • letrec* 評価モデルでは、束縛が再帰的でありながら順序もあるため、コンパイラが解析しにくい

    • レコード型の場合、vtableコールバックが多くのコードを残してしまう
  • display のように多相性の高い関数を使うと、関連する多くのコードが含まれる

    • write-string など具体的な関数を使うほうがよい
  • 最適なTree-shakingのためには、flow analysisが必要

    • display にbitvector引数が渡されないと分かれば、関連コードを除去できる
  • Pythonでは、動的ディスパッチ、__getattr__ などの動的機能のためさらに難しい

    • Pythonのモジュール構造もTree-shakingを複雑にする要因

要約

  • GCサポートにより、WebAssemblyでJavaScript以外の言語によるDOMプログラミングが可能になる
  • しかし成果物のサイズを十分小さくするには、各言語ツールチェーンへの相当な投資が必要
  • Tree-shakingアルゴリズムを適用した別個のツールチェーン開発や標準ライブラリ最適化などが求められる

GN⁺の見解

  • WebAssemblyがGCをサポートすることで、Web開発にさまざまな言語を使えるようになったが、既存言語のツールチェーンをそのまま持ち込むには難しさが多いように見える。Web環境に特化した言語実装と最適化手法が開発される必要がありそうだ。

  • Tree-shakingが動的型付け言語でうまく機能するには、静的解析が不可欠だと思われる。だがPythonのような言語は動的機能が多く、簡単ではなさそうだ。いっそ最初から静的解析に有利な言語を新たに作るのも方法かもしれない。

  • HootやTinyGoのような実験的プロジェクトはよい参考になりそうだ。だがこうしたプロジェクトを実際の製品に適用するには、まだ時期尚早かもしれない。段階的に改善していくしかなさそうだ。

  • パフォーマンスにそれほど敏感でなく、迅速な開発が重要なプロジェクトなら、Pyodideのようなものを使ってみる価値はありそうだ。だがユーザー体験を重視する製品なら、現時点ではJavaScriptが最善の選択に思える。

  • WebAssembly自体にTree-shakingのような機能を入れることも考えられそうだ。だが言語ごとに要件が異なるため簡単ではないだろう。またTree-shakingをうまく支援する言語が登場すれば、むしろその言語でコーディングするほうが得かもしれない。WebAssemblyとプログラミング言語の役割分担がどうなっていくのか興味深い。

1件のコメント

 
GN⁺ 2024-04-15
Hacker Newsの意見

要約すると次のとおりです:

  • OpenEtGプロジェクトでは、Rustで書かれたWASMバイナリのサイズを400KB未満に保つために、次のような工夫を行っている
    • float の代わりに固定小数点演算を使用
    • HashMap の代わりに Vec を使用
    • 文字列の使用を最小限にする
    • 小さなアロケータ(talc)を使用
    • 依存関係を最小化(randfxhashのみを使用)
    • ジェネリクスの多様化を避ける
    • サイズを考慮したアルゴリズム設計
  • Tree-shaking は誤った命名であり、Virgilコンパイラではこれを Reachability Analysis と呼んでいる。コンパイル過程で main エントリポイントから探索し、到達可能なコードだけを最終バイナリに含める。
  • WasmGCのおかげで、JavaやKotlinは2〜3KB程度の小さなWASMバイナリを生成できる。ただし、APIの選択には注意が必要。
  • WASMを使ったDOM操作は依然としてJS依存である。
  • Tree Shaking という用語が生まれたのは、Dead Code Elimination がかなり以前から存在していたためである。
  • WASMのコードサイズ問題は、言語ランタイムと標準ライブラリの両方をバンドルしなければならないことから生じる。
  • これを解決するために、共有ライブラリ動的リンキング を検討できる。
    • Pyodideは動的リンキングをサポートする代表的な例
    • ブラウザが人気のある言語ランタイムを事前に読み込めば、Webページでそのランタイムを共有できる
  • Zig言語は小さなWASMバイナリの生成に適している。ただし、100KB未満であればサイズは重要な要素ではない。
  • 組み込みGCはすべてのアプリにとって重要というわけではなく、GCのないWebアプリを作るのが望ましい。
  • WASMを使うアプリの成功要因は、依然として性能向上である。
  • ClojureScript、TypeScript、ReasonML などの compile-to-JS 言語を通じて、かなり以前からJS以外の言語でDOMプログラミングを行ってきた。
  • asm.jsとemscriptenを通じて、WASM以前にもC系言語をWeb上でコンパイルして利用していた。
  • Google MapsとGoogle EarthはWASMを使う代表的なアプリである。