.NETはもっと速く?マイクロソフトのソフトウェアエンジニアによるモンスター級の投稿で、大幅な改善が明らかに

Table of Contents

.NETはもっと速く?マイクロソフトのソフトウェアエンジニアによるモンスター級の投稿で、大幅な改善が明らかに

Microsoft パートナー ソフトウェア エンジニアの Stephen Toub 氏による素晴らしい投稿によると、近々登場する .NET 6 は、以前のバージョンよりも大幅に高速になるそうです。

Toub 氏の 45,000 語に及ぶ投稿は、.NET Core 2.0 以降の以前のバージョンでの同様の投稿に続くもので、パフォーマンスに影響を与える可能性のあるすべてのマージされたプル リクエスト (PR – コードの変更) の分析に基づいています。

550 件の候補のうち約 400 件の PR がカバーされていますが、.NET 5 の場合は 250 件です。これらの投稿にはパフォーマンスのヒントや、Microsoft のクロスプラットフォーム ランタイムの内部動作に関する詳細な情報が含まれているため、.NET 開発者にとっては常に調査する価値があります。

「.NET 6.0 はどれくらい高速化するのか?」という問いに対する答えは一つではありません(むしろ、遅くなる場合もあるかもしれません)。Toub 氏が提供しているのは、現在後期プレビュー段階にある .NET 6.0 で生成されたコードのパフォーマンスとサイズを、.NET Framework 4.8(旧式の Windows 専用 .NET の最終バージョン)および .NET 5.0(最新リリース)と比較したベンチマークコードです。

.NET 6.0ランタイムは長期サポートリリースであるため、特に重要です。Toub氏が各ケースについて投稿したベンチマークを見ると、結果はさまざまですが、25%程度が一般的です。

この例では、.NET 6.0は以前のバージョンよりも約25%高速ですが、生成されるコードサイズはわずかに大きくなります。

.NET 6.0では大幅な高速化が実現されています。この例では、.NET 6.0は以前のバージョンよりも約25%高速化されていますが、生成されるコードサイズは若干大きくなります。

.NET 6.0 では、場合によっては処理時間がほぼゼロにまで短縮されます。例えば、現在のプロセスのパスを取得するための新しいEnvironment.ProcessPath API は、 Process.GetCurrentProcess().MainModule.FileNameを使用した従来のアプローチと比較して、72,000 倍高速で、コードも生成されません。同様に、新しいオプティマイザーがコード内の関数が常に同じ入力(定数として定義)を持つことを検知し、関数全体を定数に置き換えるという興味深いケースもあります。これにより、処理時間とサイズがほぼゼロにまで削減されます。

後者の場合、.NET 6.0 で新たに導入された動的プロファイルガイド最適化 (PGO) と呼ばれる手法が使用されます。これは、コンパイラがインストルメンテーションを使用して最初のコンパイルを実行し、その結果を使用して 2 回目のコンパイルを最適化するという考え方です。

Toub 氏は次のように述べていることに注意してください。「.NET 6 では、動的 PGO はデフォルトでオフになっています。有効にするには、DOTNET_TieredPGO 環境変数を設定する必要があります。」

トーブ氏はまた、ファイルの読み書きに使用されるFilestreamコードが.NET 6.0で書き直されたと述べた。「FileStreamは長年にわたり、パフォーマンス関連の問題に悩まされてきました。そのほとんどはWindowsにおける非同期I/O実装に起因しています」とトーブ氏は述べ、新バージョンでは「これらの問題はすべて解決されている」と主張した。

もう一つの変更点は、.NET 6.0 コード内の 2,300 を超える「内部およびプライベート」クラスが新たにシール済みとしてマークされたことです。シールされたクラスは継承できません。つまり、コンパイラは仮想メソッド(継承された場合は別のコードでオーバーライドできます)が実際にはオーバーライドされていないと推測できるため、この別のコードを探す必要がなくなります。

ネットワークでは、WebSocket経由で送信されるデータをメッセージごとに圧縮できるようになりました。これはトレードオフですが、圧縮には処理時間がかかりますが、メッセージが小さくなるため転送速度が速くなります。「レイテンシの長い実ネットワークで通信する場合、これは良いトレードオフになる可能性があります」とトーブ氏は述べています。

  • マイクロソフト、次期バージョンでVisual Studio JavaScriptプロジェクトを刷新
  • Microsoft は .NET 6 と C# 10 の最新プレビューをリリースしましたが、C# は C++ と同じくらい複雑になりつつあるのでしょうか?
  • マイクロソフトは、JavaScriptのジャストインタイムコンパイルを無効にするとブラウザのセキュリティが向上するかどうか疑問視している
  • Stack Overflow調査:Microsoft IDEが優勢、AWSの後ろでGCPとAzureが激戦

Blazorと呼ばれる最近のフレームワークは、.NETコードをWebブラウザでWebAssemblyとして実行できることを意味します。Microsoftはこれを.NET 6.0向けに最適化することに多大な労力を費やしてきました。

Blazorでは、「ランタイムを含む.NETアプリケーション全体がブラウザにダウンロードされ、実行されます」とToub氏は説明した。.NET 5.0でのHello World Blazorアプリケーションのサイズは約2.10MBである。.NET 6.0では、彼が投稿で詳述した理由により、このサイズは1.88MBに減少する。Emscriptenベースの追加ツールを使用すると、サイズは1.82MBに減少する。

ここでToub氏は便利なヒントを付け加えました。.NETのグローバリゼーションルーチンには、様々な言語や文化に合わせて出力をフォーマットするためのコードが大量に含まれています。もしこれが不要であれば、開発者が設定できるスイッチを使うことでサイズをさらに削減し、わずか1.07MBにまで縮小できます。残念ながらこれはHello World用であり、実際のBlazorアプリケーションではおそらくもっと大きくなるでしょうが、それでも素晴らしい結果です。

Toub氏は、BlazorランタイムがMonoベースであることにも言及しました。「dotnet/runtimeには、coreclrとmonoという2つのランタイム実装があります。Blazor WebAssemblyはmonoをベースにしており、長年にわたり、こうしたシナリオ向けに小型で俊敏性を高めるよう改良が重ねられてきました。また、.NET 6ではパフォーマンス面でも大きな投資が行われています。」

その他のパフォーマンス技術には、よりスマートなコードのインライン化 (呼び出された場所にコードをコピーする)、構造体などの値型の最適化、コンパイルされたコードを移動して CPU がより効率的にフェッチできるようにするループ アライメント、型がインターフェイスを実装しているかどうかをチェックするコードのパフォーマンス向上、疑似乱数用のアルゴリズムの新しい高速実装 (ただし、シードが提供されている場合は互換性の理由から古いアルゴリズムが使用されます) などがあります。

素晴らしいですね。しかし、なぜ.NET用の単一ファイル実行ファイルをコンパイルできるネイティブコードコンパイラがないのでしょうか?その答えは、.NETランタイムフォームファクターに関するこちらの投稿にあります。.NETチームが次のように説明しています。

Microsoft は、すべての .NET コードが恩恵を受けられるように、小さな改善を .NET ランタイムに少しずつ取り入れることを選択しました。ただし、トレードオフを追求する価値があると考える人のために、実験的な NativeAOT プロジェクトがまだ存在しています。®

Discover More