HN 日本語サマリー

← 一覧へ戻る
プログラミング

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

C# now beats Rust on WASM size (github.com)

118 pointsby sumnole58 コメント

要約

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%小さい。

[画像: 生およびBrotli-11サイズのWasmフットプリントランドスケープ。精密GC搭載のNetWasmは生サイズ47,798バイト、圧縮サイズ13,501バイト。Rustは53,635バイトと16,963バイト。Kotlin/Wasmは79,293バイトと22,655バイト。TinyGoは93,043バイトと26,931バイト。NetWasmとRustは一致するWASI Preview 2の比較。KotlinとTinyGoは文脈上のPreview 1の参照。]

ツールチェーン生WasmBrotli 11比較対象
NetWasm 0.8.0, コンパクトGC47,798 B13,501 BWASI P2コンポーネント; 精密GC込み
Rust 1.95.0, サイズプロファイル53,635 B16,963 B一致するWASI P2コンポーネント参照
Kotlin 2.4.0 wasmWasi79,293 B22,655 BP1コンテキスト; GCはホストエンジンにより提供
TinyGo 0.39.093,043 B26,931 BP1コンテキスト; 精密GC設定済み

Rustが主要な比較対象となるのは、同じワークロードと出力形式を使用しているためです。Kotlin/WasmとTinyGoは、より広範なフットプリントの状況を示していますが、それらのターゲットとランタイムの境界は異なります。これは測定されたワークロード/プロファイルの結果であり、言語全体でのサイズランキングではありません。

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

Mono AOTよりも高速

0.10.0現在、NetWasmは同じC#ソースからコンパイルされ、同じWasmtimeで実行された割り当ておよびガベージコレクションのベンチマークにおいて、Mono AOTよりも高速に動作します。

ワークロードNetWasm 0.10.0, NetWasmGCMono AOT, .NET 10NetWasm時間
フル・トランザクション43.9 ms59.1 ms26%削減
保持オブジェクトグラフ8.8 ms14.2 ms38%削減
UIチャーン17.6 ms29.1 ms40%削減

これらは、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は以下のことが可能です。

  • 通常のdotnet CLIを介してプロジェクトをビルド、実行、発行、テストする。
  • 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#を可能にしています。

JSONとオプション機能がサイズにどう影響するか

割り当て戦略を選択する

Compactはデフォルトであり、サイズ優先、精密、非移動型のマークアンドスイープコレクタです。コンパイラによって公開されたルートと参照レイアウトを、コンサバティブスキャンなしでトレースします。その名前は、ヒープコンパクションの移動ではなく、実装サイズを指します。

戦略最適な用途生コンポーネントBrotli 11
Compact (デフォルト)小規模アプリケーションおよび低チャーンUI47,895 B13,660 B
NetWasmGC高い割り当てスループット50,855 B15,053 B
Bump境界のある、一度きりのジョブ43,864 B11,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サイズ比較、小さいほど良い: コンパクトGC搭載のNetWasm 46.7 KiB、Blazor .NET 10 11.71 MiB、Blazor .NET 11 RC1 14.58 MiB。NetWasmは、バイト単位で.NET 11ビルドの約320倍小さい。]

AOTビルド非圧縮WasmNetWasmに対する相対値
NetWasm 0.8.0, コンパクトGC47,798 B1×
Blazor WebAssembly, .NET 1012,276,684 B257×
Blazor WebAssembly, .NET 11 RC115,289,241 B320×

Blazorの合計には、ネイティブランタイムと必要なWebcilアセンブリが含まれます。NetWasmには、ランタイム、ガベージコレクタ、およびWASIコンポーネントが含まれます。これはコンソールコンポーネント対空のUIアプリケーションであり、同等のフレームワーク比較や、すべての.NETワークロードに関する主張ではありません。

正確なBlazorバージョン、設定、および再現手順

現在の境界

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、および名前付きカルチャグローバリゼーションは、初期互換性スライス外のままであり、コンパイル時に失敗します。

完全な1.0ロードマップを読む

パッケージ

コンパイラ、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

ポートされたライブラリパッケージ · TUnitパッケージ

ライセンス

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のサポート境界を決定する方法です。