速いので使いたい
私の場合、ここ数か月で一番素晴らしいニュースだと感じたブログがこれでした。
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/
.NET5 がどれだけパフォーマンス向上のために努力してきたかという内容です。
ものすごいボリュームで読むのが大変でしたが、満足感のある記事でした。
この記事を読んだだけでも、早く.NET 5 を使いたいという気持ちになりました。
パフォーマンスが良くなったという知らせはいつでもエンジニアの気持ちを高揚させるのだと思います。
使いたい理由1 : GCが高速化した
いくつものアプローチを重ねたことが記されていました。
- GCが到達可能オブジェクトをマークする処理の情報を他のスレッドでも流用できるようにして、各スレッド内の同処理の作業量を一部省略可能にした
- GCのGen0,1が使用する近傍のメモリのデコミット(OSにメモリ返却する処理)を最適化した。メモリが返却されてもGen0,1の領域はすぐに再確保が必要になる可能性があり、その頻度を減らすことを目的とする
- GCの統計手法の変更により、GCのスキャン競合によるロックを減らすことに成功した。これによりマルチコア時のスケーラビリティが改善する
- Intel AVX512 に対応することでGC内のソートを高速化した(並び替えをベクター化することに合わせて導入)
- バックグラウンドGCの進行中にフォアグラウンドGCのサスペンド処理自体を高速化することで、ロック時間を短縮した
要約してはみたものの、ソースコードや解説を見ても分からないものも結構ありました。
使いたい理由2 : coreclr(C/C++)からcorelib(C#)への移植が進んだ
GCの最適化と並行してC/C++ネイティブ実装のcoreclrをC#実装のcorelibに移植する作業も進められたそうです。
基本的にC#は安全なものなので、ネイティブ実装が減れば減った分、安全性が増します。
しかし恩恵はそれだけにとどまりません。coreclr内のネイティブコードが動作している間、GCですらもその終了を待つことになります。つまりネイティブ実装が減りC#実装が増えたことにより、GC自体が待つことが減ります。
結果として、GC.Collect()
による遅延時間は非常に短縮されます。
使いたい理由3 : Span<T>.Sort
によるArray.Sort
ソートは大変重い処理でありながら、私たちはこれを避けることができません。しかし、Span<T>.Sort
が追加されたことで状況は変わります。
https://docs.microsoft.com/ja-jp/dotnet/api/system.memoryextensions.sort?view=net-5.0
前述のcorelib化の恩恵でソート自体が高速化しました。C#のソートは一般に配列に対するものですが、これをSpanで実行することで配列の境界チェックの処理などをかなり節約することができるようです。
またArray.Sort
が内部的にSpan<T>.Sort
で動作するようになり、.NET Framework 4.8と比べて約2倍、.NET Core 3.1 と比べても数十%の優位があります。
使いたい理由4 : 配列やSpan<T>
に対するC#コンパイラやJITの最適化が素晴らしい
.NET Core 3.1 でもかなりの最適化が施されていましたが、さらにさらに強化されました。
最適化の多くは、何度も同じ処理を繰り返さないことと、不要と確定している判定を除去することが主体となります。
- メソッドローカルの
ReadOnlySpan<T>
はスタックではなくstatic領域に固定的に保持されるようになった - 16バイト未満の配列からの積極的な境界判定の削除
- 初期化の必要がない
Span<T>
を初期化しない
などなど。
これらについては種類が多すぎて語りつくせません。
ただ言えることは、配列の境界判定のような処理が減るだけで、コードサイズは減り、処理時間も減り、良いことづくめであるということです。
配列とSpan<T>
関連についてはともかく強くなったということです。
使いたい理由5 : 型の扱いも速くなった
C#キャストは内部的にはCastHelper
というクラスによってキャッシュされています。この実装が改善されたため(ref
を多用した形に変わっていました)キャストの速度は格段に向上しました。
キャスト以外にも、ジェネリックメソッドのスロットの汎用化が進み、ジェネリックメソッドの呼び出しコストが小さくなりました。
このようにRuntimeHelper群の最適化が進みました。
使いたい理由6 : ライブラリ群のパフォーマンスが改善されている
- 文字列処理
- 正規表現
- async/await
- コレクション
- LINQ
- ネットワーキング
まとめ
このどれもが、既存のコードを書き換えずとも恩恵を受けることができるということがポイントとなります。
この記事にはソースコードやベンチマーク結果を掲載しません。なぜなら、冒頭のリンク先にすべてあるからです。
.NET 5 は素晴らしいものです。このパフォーマンス改善だけでも、.NET 5 に移行する動機づけとなる可能性があります。
謝辞
冒頭でリンクしたブログの内容は本当に素晴らしいものでした。Stephen Toub氏に感謝いたします。
また、.NET と C# の進歩と高速化に日々貢献してくださっているすべてのエンジニアに感謝いたします。
ご案内
「.NET 5 を使いたい理由」シリーズをいくつか予定しています。
次の記事は私の所属先のお客様である 弥生株式会社様の Advent Calendar 2020 で 12/3 に公開予定です。
https://qiita.com/advent-calendar/2020/yayoi
ご覧いただければ嬉しく思います。