C#がWASMサイズでRustを上回る
C# now beats Rust on WASM size (github.com)
要約
NetWasmプロジェクトは、C#コードをWebAssembly(Wasm)に直接コンパイルする新しいアプローチです。このプロジェクトは、特定のベンチマークワークロードにおいて、Rustよりも小さいWasmバイナリサイズを実現し、Mono AOTよりも高速なパフォーマンスを示すことを発表しました。NetWasmは、WasmおよびWASI向けに、小さく独立した.NETプラットフォームを提供することを目指しています。
全文翻訳
WebAssemblyおよびWASI向けの独立した.NET。
C#で記述し、小さくスタンドアロンなWasmとしてデプロイします。
NetWasmは、C#および.NET CILを直接WebAssemblyにコンパイルする独立したコンパイラ、CoreLib、ランタイム、およびSDKです。本番環境にはデスクトップCLR、Mono、dotnet.js、またはアプリケーションDLLを持ち込みません。
[画像: GitHubでNetWasmをスターする] [画像: リリース] [画像: ライセンス: コミュニティ + MIT]
C#をWebAssemblyにコンパイル · ブラウザで試す · インストールとビルド · サポートされているAPIを確認 · ドキュメントを読む
C#がWasmサイズでRustを上回る
NetWasm 0.8.0 + 精密GC: 47,798バイト
Rust 1.95.0 サイズ重視プロファイル: 53,635バイト
同じprint-42ワークロードにおいて、NetWasmの結果にはランタイムと精密なコンパクトガベージコレクタが含まれています。どちらの成果物も、サイズ重視の設定でビルドされたスタンドアロンのWASI Preview 2コンポーネントです。
生のサイズで10.9%小さく、Brotli-11圧縮で20.4%小さい。
| ツールチェーン | 生Wasm | Brotli 11 | 比較対象 |
|---|---|---|---|
| NetWasm 0.8.0, コンパクトGC | 47,798 B | 13,501 B | WASI P2コンポーネント; 精密GC込み |
| Rust 1.95.0, サイズプロファイル | 53,635 B | 16,963 B | 一致するWASI P2コンポーネント参照 |
Kotlin 2.4.0 wasmWasi | 79,293 B | 22,655 B | P1コンテキスト; GCはホストエンジンにより提供 |
| TinyGo 0.39.0 | 93,043 B | 26,931 B | P1コンテキスト; 精密GC設定済み |
Rustが主要な比較対象となるのは、同じワークロードと出力形式を使用しているためです。Kotlin/WasmとTinyGoは、より広範なフットプリントの状況を示していますが、それらのターゲットとランタイムの境界は異なります。これは測定されたワークロード/プロファイルの結果であり、言語全体でのサイズランキングではありません。
Mono AOTよりも高速
0.10.0現在、NetWasmは同じC#ソースからコンパイルされ、同じWasmtimeで実行された割り当ておよびガベージコレクションのベンチマークにおいて、Mono AOTよりも高速に動作します。
| ワークロード | NetWasm 0.10.0, NetWasmGC | Mono AOT, .NET 10 | NetWasm時間 |
|---|---|---|---|
| フル・トランザクション | 43.9 ms | 59.1 ms | 26%削減 |
| 保持オブジェクトグラフ | 8.8 ms | 14.2 ms | 38%削減 |
| UIチャーン | 17.6 ms | 29.1 ms | 40%削減 |
これらは、Wasmtime 49.0.3上のApple M1 Maxで15回実行した中央値であり、各実行はデスクトップ.NETの結果と比較されています。Mono AOTは、Microsoftのwasi-wasmターゲットであり、デフォルトのRelease設定です。NetWasmGCは、デスクトップ.NET 11のJITよりも最初の2つのワークロード(49.9 msおよび9.7 ms)で時間がかかりません。JITはUIチャーン(8.6 ms)でより高速であり、デスクトップNativeAOTは3つすべてで最も高速です。
Hello World以上
46.7 KiBのプログラムはベースラインであり、境界ではありません。
C# 15 · JavaScriptモジュールとWeb Worker · 静的.a相互運用 · WIT/WASI P2 · 式ツリー · HTTP/JSON/XML/Regex · リフレクションフリーDI · TUnit/VSTest · wasm64 · 4つの割り当て戦略
現在、NetWasmは以下のことが可能です。
- 通常の
dotnetCLIを介してプロジェクトをビルド、実行、発行、テストする。 - C#エクスポートを、ページ内またはWeb Workerで実行される型付きJavaScriptモジュールとして発行する。
- 互換性のあるWasm
.aアーカイブをリンクし、境界のあるC ABIマーシャリングを生成する。 - WITからC#バインディングを生成し、スタンドアロンのWASI P2コンポーネントを生成する。
- 一般的なランタイムリフレクションなしで、式ツリーを構築および検査する。
- 個別にパッケージ化されたLINQ、HTTP、JSON、XML、Regex、Hashing、および依存性注入ライブラリを使用する。
- ライブラリを
netwasm0.1とデスクトップ.NETの両方にターゲットする。
プロファイルは意図的にデスクトップ.NETよりも小さくなっています。すでに完全なアプリケーション、ポータブルライブラリ、テストプロジェクト、およびブラウザモジュールをサポートしています。
試してみる
.NET SDK 10.0.303以降をインストールし、以下を実行します。
dotnet new install NetWasm.Templates
dotnet new netwasm-app -n HelloNetWasm
cd HelloNetWasm
dotnet restore
dotnet run
dotnet publish -c Release -o publish/local
発行されたコンポーネントを、Wasmtimeのような互換性のあるWASI Preview 2ホストで実行します。
wasmtime run publish/local/HelloNetWasm.wasm
42
発行されたコンポーネントは.NETに関して自己完結型です。WebAssemblyホストは依然として必要です。.NETでビルドし、.NETなしで実行します。
C# 15を使用するプロジェクトは.NET 11 SDKを選択します。それ以前の言語バージョンは.NET 10のままで構いません。SDKはNuGet経由でピン留めされたNode、LLD、Binaryenツールを復元するため、通常のアプリケーションは個別のEmscripten、Git、またはPythonのインストールを必要としません。ホスト、復元、Windows、ブラウザ、およびデュアルターゲットの詳細については、完全なクイックスタートを参照してください。
小ささを維持する方法
RoslynはCILを生成します。NetWasmは到達可能なプログラムを直接Wasmにコンパイルし、ジェネリックスを特化させ、必要なランタイムサポートのみをリンクします。リンクされたWasmコンポーネントがプログラムです。
- クローズドワールドコンパイル。 到達不可能なコード、インポート、およびランタイム機能は成果物に含まれません。
- より小さなプラットフォーム契約。 NetWasmは、すべてのデスクトップランタイムの前提条件を再現するのではなく、ポータブルAPIをサポートします。
- 広範なランタイムリフレクションなし。 ランタイム型名、動的アセンブリロード、および
dynamicキーワードはプロファイルの外です。 - 生成された境界。 JSON、DI、WIT、およびネイティブ相互運用は、ランタイム検出ではなく既知の契約を使用します。
- オプションのデータと診断。 タイムゾーンデータ、リッチなスタックトレース、およびその他のデプロイメントデータは、選択された場合にのみ含まれます。
- 1つのコレクタ。 選択された割り当て戦略のみがリンクされます。
これは新しい.NETプラットフォームであり、Wasmサンドボックスに押し込まれたデスクトップ.NETではありません。その境界が、ネイティブWasmサイズのC#を可能にしています。
割り当て戦略を選択する
Compactはデフォルトであり、サイズ優先、精密、非移動型のマークアンドスイープコレクタです。コンパイラによって公開されたルートと参照レイアウトを、コンサバティブスキャンなしでトレースします。その名前は、ヒープコンパクションの移動ではなく、実装サイズを指します。
| 戦略 | 最適な用途 | 生コンポーネント | Brotli 11 |
|---|---|---|---|
| Compact (デフォルト) | 小規模アプリケーションおよび低チャーンUI | 47,895 B | 13,660 B |
| NetWasmGC | 高い割り当てスループット | 50,855 B | 15,053 B |
| Bump | 境界のある、一度きりのジョブ | 43,864 B | 11,959 B |
実行可能プロジェクトの.csprojで戦略を選択します。
<PropertyGroup>
<NetWasmGarbageCollector>NetWasm</NetWasmGarbageCollector>
</PropertyGroup>
プロパティを設定しない場合、Compactが選択されます。ライブラリはコレクタニュートラルなままです。すべての4つのバックエンドがwasm32およびwasm64用にパッケージ化されています。トレードオフと診断については、ガベージコレクタの選択を参照してください。
ライブラリは上に移動すべき
より小さなNetWasmプロファイルのために書かれたライブラリは、Wasm専用のエコシステムに閉じ込められるのではなく、デスクトップ.NETでも有用であるべきです。
dotnet new netwasm-lib -n MyLibrary
このテンプレートはnetwasm0.1とnet10.0をターゲットとし、両方のプラットフォーム用のNuGetアセットを生成します。これは明示的なマルチターゲティングであり、任意のデスクトップパッケージが逆に機能するという保証ではありません。
NetWasm.Librariesは、ポートされたフレームワークおよび拡張機能パッケージを提供します。TUnit-NetWasmは、汎用VSTestブリッジを介して通常のdotnet test統合を提供します。
従来の.NET Wasmと比較してどうか?
空のUIを持つBlazor WebAssemblyアプリケーションが42を出力する場合、AOT、マネージドトリミング、ILストリッピング、不変グローバリゼーション、およびサイズ重視のネイティブリンクを有効にした場合:
| AOTビルド | 非圧縮Wasm | NetWasmに対する相対値 |
|---|---|---|
| NetWasm 0.8.0, コンパクトGC | 47,798 B | 1× |
| Blazor WebAssembly, .NET 10 | 12,276,684 B | 257× |
| Blazor WebAssembly, .NET 11 RC1 | 15,289,241 B | 320× |
Blazorの合計には、ネイティブランタイムと必要なWebcilアセンブリが含まれます。NetWasmには、ランタイム、ガベージコレクタ、およびWASIコンポーネントが含まれます。これはコンソールコンポーネント対空のUIアプリケーションであり、同等のフレームワーク比較や、すべての.NETワークロードに関する主張ではありません。
現在の境界
NetWasmは1.0未満です。サポートされているプロファイルは現在使用可能であり、公開された認定によってカバーされていますが、ソース、パッケージ、ターゲットプロファイル、およびABIの契約はマイナーリリース間で変更される可能性があります。
通常のポータブル出力は、wasm32 WASI Preview 2コンポーネントです。生のwasm32、生のwasm64、およびJavaScriptホスト統合は高度な代替手段です。wasm64コンポーネントは、アップストリームツールによってブロックされたままです。
ランタイムリフレクション、dynamic、ランタイムアセンブリロード、およびマネージドスレッドはプロファイルの外です。一般的なSystem.IO.File/Directory/FileStream、生のソケット、およびサブプロセスAPIはまだ実装されていません。既存のNuGetパッケージは、到達可能なコードとAPIの依存関係がサポートされているプロファイルに適合する場合にのみ機能します。
サポートされているAPIと制限事項 · ドキュメントインデックス
1.0へのロードマップ
NetWasm 1.0は、有用で、文書化され、安定した、より小さなプラットフォームを意味します。「Wasm内のデスクトップ.NET」を意味するわけではありません。主な残りのテーマは以下の通りです。
- より広範なWASI Preview 2カバレッジ。
- グローバリゼーションモードとオプションのカルチャデータ。
- 式ツリーの完了。
- より高速な増分開発ループ。
- 安定した
netwasm1.0プラットフォームとランタイム契約。 - 本番環境の診断とより広範なホスト認定。
NetWasm 0.10.0の新機能: 再構築されたガベージコレクタ。オブジェクトはコレクタヘッダーを持たず、配列は単一の割り当てであり、NetWasmGCはポインタを進めることで割り当てを行い、Compactはサイズとメモリのために新しく構築されたコアを持っています。割り当て負荷の高いプログラムはより高速に動作し、メモリ使用量が大幅に削減され、タイムゾーンデータを配布するアプリケーションはわずかな時間で起動します。Boehmコレクタは削除されました。リリースノート
進行中: 既存の.NET Standard 2.1ライブラリバイナリおよびNuGetアセットとの互換性の向上。目標は、到達可能なコードがNetWasmプロファイルに適合する場合、不要なサポートされていないパスをアプリケーションに持ち込むことなく、ライブラリをそのまま消費できるようにすることです。
これはNetWasmをデスクトップ.NETに変えるものではありません。到達可能な一般的なランタイムリフレクション、dynamic、ランタイムアセンブリロード、マネージドスレッド、サポートされていないホストAPI、および名前付きカルチャグローバリゼーションは、初期互換性スライス外のままであり、コンパイル時に失敗します。
パッケージ
コンパイラ、SDK、ランタイム、およびホスティングパッケージ
NetWasm.Compiler.Browser · NetWasm.Compiler.Tasks · NetWasm.Hosting · NetWasm.Hosting.Build · NetWasm.Ref · NetWasm.Runtime.Pack · NetWasm.Runtime.Wasm32 · NetWasm.Runtime.Wasm64 · NetWasm.Sdk · NetWasm.Templates · NetWasm.Testing.VSTest · NetWasm.Toolchain · NetWasm.Wit.Bindings.Tool
ライセンス
CoreLib、ランタイムライブラリ、テンプレート、および生成されたサポートコードはMITライセンスであり、アップストリームの通知は保持されます。コンパイラと開発者ツールはNetWasmコミュニティライセンス1.0を使用します。CompactおよびNetWasmGCコレクタはApache-2.0ライセンスです。
コミュニティライセンスは、資格のある個人、教育機関、オープンソースプロジェクト、評価、および従業員250人未満で年間収益1,000万米ドル未満の組織には無料で提供されます。GitHub Sponsorsティアに一致するスポンサーシップは、限定的な社内商用利用を許可します。OEMおよび商用提供の利用には別途契約が必要です。生成されたアプリケーションは、作成者の選択したライセンスを使用できます。サインイン、アクティベーション、テレメトリ、または技術的な強制はありません。
ライセンスガイド · サードパーティ通知 · 商用ライセンス: zionsatidev@gmail.com
ワークロードを持ち込む
Console.WriteLine(42)から始め、次にデプロイサイズ、サンドボックス化、またはポータビリティが重要な最小の実際のワークロードを試してください。何かが不足している場合は、Issueを開いてください。具体的なワークロードが、1.0のサポート境界を決定する方法です。