NetWasm 0.10.0 により、C# が WebAssembly サイズで Rust を上回る

C# が WebAssembly サイズで Rust を上回る

要点: NetWasm 0.10.0 は、単純な print(42) プログラムに対して 47,895 バイトのスタンドアロン WASI コンポーネントを生成します。これは Rust 1.95.0 のサイズ最適化バイナリ (53,635 B) より 10.7% 小さく、Brotli-11 圧縮後は 19.5% 小さくなります。

生サイズと圧縮サイズの比較

結果: NetWasm の Compact GC ビルドは生サイズ 47,895 B、圧縮サイズ 13,660 B です。Rust のサイズ最適化ビルドは生サイズ 53,635 B、圧縮サイズ 16,963 B です。

ツールチェーン 生 Wasm Brotli-11 役割
NetWasm, Compact GC 47,895 B 13,660 B 組み込みの正確な GC を備えた WASI Preview 2 コンポーネント
Rust 1.95.0, size profile 53,635 B 16,963 B 同等の WASI Preview 2 コンポーネント
Kotlin 2.4.0 wasmWasi 79,293 B 22,655 B Preview 1; ホストが GC を提供
TinyGo 0.39.0 93,043 B 26,931 B Preview 1; カスタム GC

両バイナリはデフォルトのリリース設定で生成され、手動による後処理は行われていません。NetWasm のコンパイラパイプラインは常に Binaryen の wasm-opt を実行しますが、Rust のビルドには同等のステップが含まれていません。これは、コンポーネント形式が再エンコードを複雑にするためです。

方法論に関する注記

  • Rust ビルドは opt-level = "z"、LTO、単一コード生成ユニット、panic = "abort"、シンボル削除を使用します。
  • NetWasm のサイズには、ランタイムと正確な Compact ガベージコレクタが含まれます。
  • ベンチマークは単一の print(42) ワークロードを反映しており、言語全体のサイズランキングではありません。
  • 両ツールチェーンは、no_std (Rust) またはゼロライブラリアプローチ (C#) でさらに縮小できますが、これらの構成は標準ライブラリの大部分を犠牲にし、C# の場合はガベージコレクタも犠牲にします。

正確なソース、バージョン、設定、再現手順

Mono AOT に対するパフォーマンス上の利点

要点: NetWasm の割り当ておよび GC ベンチマークは、同じ C# ソースからコンパイルされ Wasmtime で実行された Mono AOT よりも 26〜40% 高速です。

ワークロード NetWasm (Compact GC) Mono AOT (.NET 10) 速度向上
完全なトランザクション 43.9 ms 59.1 ms 26% 高速
保持オブジェクトグラフ 8.8 ms 14.2 ms 38% 高速
UI チャーン 17.6 ms 29.1 ms 40% 高速

測定は、Apple M1 Max 上で Wasmtime 49.0.3 を使用した 15 回の実行の中央値です。NetWasm は、最初の 2 つのワークロードではデスクトップ .NET 11 JIT も上回りますが、JIT は UI チャーンではわずかに高速です。Native AOT は全体として最速のままです。

バージョン、設定、デスクトップ数値、再現

hello-world を超える機能セット

要点: NetWasm は、フル機能の C# 15 アプリケーション、JavaScript 相互運用、静的 .a アーカイブ、WIT バインディング、式ツリー、HTTP/JSON/XML、リフレクションフリーの DI、および wasm32 と wasm64 の両ターゲットをサポートします。

  • 標準の dotnet CLI を使用してビルド、実行、発行、テストが可能。
  • ブラウザまたは Web Worker 向けの型付き JavaScript モジュールをエクスポート。
  • 生成された C ABI マーシャリングを使用してネイティブ .a アーカイブをリンク。
  • WIT から C# バインディングを生成し、スタンドアロンの WASI Preview 2 コンポーネントを生成。
  • NetWasm 用にパッケージ化された LINQ、HTTP、JSON、XML、Regex、DI ライブラリを使用。
  • netwasm0.1 とデスクトップ .NET 向けのデュアルターゲットライブラリ。

プロファイルは意図的にデスクトップ .NET よりも小さくなっていますが、完全なアプリケーション、ポータブルライブラリ、テストプロジェクト、ブラウザモジュールをすでにサポートしています。

クイックスタートガイド

要点: .NET 10+ SDK と NetWasm テンプレートをインストールすると、42 を出力する自己完結型の C# プログラムを 1 分以内でコンパイルして実行できます。

# .NET SDK 10.0.303+ をインストール (C# 15 の場合は .NET 11)
# NetWasm テンプレートをインストール

dotnet new install NetWasm.Templates

dotnet new netwasm-app -n HelloNetWasm
cd HelloNetWasm

dotnet restore

dotnet run               # 42 を出力

dotnet publish -c Release -o publish/local

# WASI Preview 2 ホスト (例: Wasmtime) で実行
wasmtime run publish/local/HelloNetWasm.wasm

発行されたコンポーネントは .NET に関して自己完結型です。実行時には WASI ホストのみが必要です。「.NET でビルドし、.NET なしで実行」。

NetWasm が小ささを維持する仕組み

要点: NetWasm は、到達可能な CIL を直接 Wasm にコンパイルし、閉世界解析を実行し、実際に使用されるランタイム機能のみをリンクすることでサイズを実現しています。

  • 閉世界コンパイル: 到達不能なコード、インポート、ランタイム機能は省略されます。
  • プラットフォーム契約の縮小: ポータブル API のみが提供され、デスクトップランタイムの前提は除外されます。
  • 広範なリフレクションなし: dynamic、ランタイムアセンブリ読み込み、一般的な型検査などの機能は省略されます。
  • 生成された境界: JSON、DI、WIT、ネイティブ相互運用は、ランタイム検出ではなく静的契約を使用します。
  • オプションデータ: タイムゾーンデータ、リッチなスタックトレース、診断は、明示的に有効にした場合のみ含まれます。
  • 単一コレクタ: 選択された GC 戦略のみが最終バイナリにリンクされます。

これは、Wasm サンドボックスに押し込まれた縮小版デスクトップランタイムではなく、目的に合わせて構築された .NET プラットフォームです。

割り当て戦略とサイズのトレードオフ

要点: NetWasm は 3 つのガベージコレクタ戦略を提供しており、それぞれサイズとパフォーマンスの特性が異なります。

戦略 最適な用途 生コンポーネント Brotli-11
Compact (デフォルト) 小規模アプリ、低チャーン UI 47,895 B 13,660 B
NetWasmGC より高い割り当てスループット 50,855 B 15,053 B
Bump 制限付きの一回限りのジョブ 43,864 B 11,959 B

プロジェクトファイルに <NetWasmGarbageCollector> を追加して戦略を選択します。プロパティを省略するとデフォルトで Compact になります。

ライブラリ互換性モデル

要点: NetWasm ライブラリは netwasm0.1 とデスクトップフレームワーク (例: net10.0) をマルチターゲットにしており、同じソースを Wasm と従来の .NET の両方で実行できます。

# 両プラットフォームをターゲットとするライブラリを作成

dotnet new netwasm-lib -n MyLibrary

生成された NuGet パッケージには両ランタイム用のアセットが含まれていますが、NetWasm プロファイルに適合するライブラリのみが変更なしで使用できます。

従来の Blazor WebAssembly との比較

要点: 42 を出力する Blazor WebAssembly AOT ビルドは約 12 MiB (.NET 10) または約 15 MiB (.NET 11) を占め、NetWasm は約 256〜319 倍大きくなります。

ビルド 非圧縮 Wasm NetWasm とのサイズ比
NetWasm, Compact GC 47,895 B 1×
Blazor WebAssembly, .NET 10 12,276,684 B 256×
Blazor WebAssembly, .NET 11 RC1 15,289,241 B 319×

Blazor の数値にはネイティブランタイムと必要なアセンブリが含まれます。NetWasm にはランタイム、GC、WASI コンポーネントが含まれます。この比較は、コンソールコンポーネントと空の UI の Blazor アプリの比較であり、フルフレームワークの同等性ではありません。

正確な Blazor バージョン、設定、再現

コミュニティフィードバックのハイライト

「これは少し不公平な比較です。ベンチマークされた C# コードは後処理も行われており、他のターゲットにはありません。… Rust はもっと小さくできます。」 – @sondr3

「C# にはバックエンドにぴったりだと感じる何かがあります…優れたツール、最新の言語機能、素晴らしいデバッグ体験。」 – @CharlieDigital

「これはオープンソースではないことを指摘しておく価値があります。2 つを比較する際にそれが重要な考慮事項であるなら (私にとっては重要です)。」 – @Scaled

「これは少し不公平な比較です。WASM には C# が使用できるガベージコレクタが付属していますが、Rust はすべてのメモリ管理を自分で行うため、当然大きくなります。」 – @weinzierl (後で投稿を読んで修正)

「それほど難しくはありません... Rust の wasm バイナリは巨大です。WASM のパフォーマンス、サイズ、メモリ使用量を気にするなら、Zig の方がはるかに良い候補です。」 – @jedisct1

これらのコメントは、ベンチマークの公平性、オープンソースライセンス、ガベージコレクタのオーバーヘッドの関連性など、主な論点を示しています。

現在のステータスとロードマップ

要点: NetWasm は 1.0 未満です。0.10.0 リリースでは、再構築されたガベージコレクタとサイズに焦点を当てた最適化が導入されています。今後の作業は、より広範な WASI Preview 2 カバレッジ、オプションのグローバリゼーションデータ、完全な式ツリーサポート、安定した netwasm1.0 契約、本番診断を対象としています。

  • 0.10.0 のハイライト: オブジェクトのコレクタヘッダーなし、単一割り当て配列、Boehm コレクタの削除、割り当ての多いプログラムの高速化、タイムゾーンデータの起動時間の短縮。
  • 1.0 への道: WASI Preview 2 API サーフェスの拡張、より多くの .NET Standard 2.1 ライブラリの有効化、プラットフォームとランタイム契約の安定化、インクリメンタル開発ループの改善。

プロジェクトは引き続き貢献を受け付けています。問題と機能リクエストを歓迎します。

ライセンスモデル

要点: NetWasm のコアライブラリは MIT ライセンスです。コンパイラとツールは NetWasm Community License 1.0 を使用しており、個人、教育、オープンソース作業、小規模組織 (従業員 250 人以下、収益 1,000 万ドル以下) には無料です。これらの制限を超える商用利用には別途契約が必要です。

  • ランタイムコレクタ (Compact、NetWasmGC) は Apache-2.0 です。
  • 生成されたアプリケーションには、アクティベーション、テレメトリ、技術的強制は組み込まれていません。

パッケージとエコシステム

  • コンパイラと SDK: NetWasm.Compiler.Tasks、NetWasm.Sdk、NetWasm.Templates
  • ランタイム: NetWasm.Runtime.Wasm32、NetWasm.Runtime.Wasm64
  • ホスティング: NetWasm.Hosting、NetWasm.Hosting.Build
  • ライブラリポート: NetWasm.Libraries スイート、TUnit-NetWasm

すべてのパッケージは NuGet で利用可能で、リポジトリに文書化されています。


Sources