この記事は機械翻訳のミラー記事です。元の記事にジャンプするにはこちらをクリックしてください。

眺める: 6846|答える: 2

[出典] [ターン]。 .NETパフォーマンス最適化 - Collections.Pooledが推奨されます

[リンクをコピー]
2022年5月29日 13:45:22に投稿 | | | |
簡単な紹介

パフォーマンス最適化とは、同じ数のリクエストを、より少ないリソース(一般的にCPUやメモリ、もちろんオペレーティングシステムのIOハンドル、ネットワークトラフィック、ディスク使用量など)で処理できるようにする方法です。 しかしほとんどの場合、CPUやメモリの使用量を削減しています。
先に共有したコンテンツにはいくつかの制約があり、直接変換するのが難しいです。今日は、いくつかのコレクションタイプを置き換えるだけでパフォーマンスを向上させ、メモリ負荷を減らす効果を得る簡単な方法を共有したいと思います。
今日はクラスの図書館をご紹介したいと思いますクラスライブラリはCollections.Pooledと呼ばれています名前からもわかるように、これはメモリの容量とGCを削減する目的を達成するためにプールされたメモリを通じて行われており、その性能を直接ご覧いただきます。また、なぜこれらの性能向上をもたらすのか、ソースコードもお見せします。

コレクション。プール

プロジェクトリンク:ハイパーリンクのログインが見えます。

このライブラリはSystem.Collections.Genericのクラスに基づいており、<T>新しいSystem.SpanおよびSystem.Buffers.ArrayPoolクラスライブラリを活用してメモリ<T>割り当ての削減、パフォーマンス向上、そして現代のAPIとの相互運用性向上を目的に修正されています。
Collections.Pooledは.NET Standnd 2.0(.NET Framework 4.6.1+)および.のサポートをサポートしています。 NET Core 2.1+。 CoreFXから移植された詳細なユニットテストとベンチマークが導入されています。

検査総数:27501。 経由:27501。 失敗:0。 スキップ:0。
試験運転は成功しました。
テスト実行時間:9.9019秒

使い方

このライブラリはNuget、NuGet Versionを通じて簡単にインストールできます。

Collections.Pooledライブラリでは、.NETネイティブ型との比較で示すように、私たちが一般的に使うコレクションタイプのプール版を実装しています。

. .NET ネイティブコレクション。プール所見
リスト<T>プールドリスト<T>汎用コレクションクラス
Dictionary<TKey、TValue>PooledDictionary<TKey、TValue>一般辞書クラス
ハッシュセット<T>プールドセット<T>汎用ハッシュコレクションクラス
スタック<T>スタック<T>汎用スタック
列<T>プールドキュー<T>ジェネリック・コホート

使用時には対応する を追加するだけでよい。 以下のコードに示されているCollections.Pooled版を用いた.NETネイティブバージョン:

ただし、Pooled型はIDisposeインターフェースを実装しており、Dispose()メソッドを通じて使用済みメモリをプールに返すため、Pooledコレクションオブジェクトを使用した後にDispose()メソッドを呼び出す必要があります。 または「using var」というキーワードを直接使うこともできます。

注意:Collections.Pooled 内のコレクションオブジェクトを使用してください手動でリリースするのが最善ですしかし、リリースしなくても問題ありません。GCは最終的にリサイクルしますが、プールに戻すことはできず、メモリ節約の効果も達成しません。
メモリ空間を再利用するため、プールにメモリ空間を戻す際にはコレクション内の要素を処理する必要があり、以下のように定義されるClearModeという列挙を提供します。




デフォルトではデフォルト値のオートを使え、特別な性能要件がある場合はリスクを把握した後にネバーを使えばよい。
参照型および参照型を含む値型の場合、メモリ空間をプールに返す際に配列参照を空にしなければなりません。クリアしなければ、GCはこの部分のメモリ空間を解放できません(要素の参照は常にプールに保持されているため)。純粋な値型の場合は空にできません。この記事では参照型とstruct(値型)配列の記憶の違いについて説明します。純粋な値型はオブジェクトヘッダーのリサイクルがなく、GCの介入も必要ありません。


. .NETパフォーマンス最適化 - struct代替クラスの使用:ハイパーリンクのログインが見えます。

性能比較

ベンチマークだけはやっていませんし、直接使ったオープンソースプロジェクトのランニングスコアは多くのプロジェクトのメモリ使用量が0でした。これはプールされたメモリに余分な割り当てがなかったからです。

プールドリスト<T>

ベンチマークでセットに追加された2048要素をループします。 .NETネイティブのList<T>は110us(実際のベンチマーク結果によると、図のミリ秒単位は事務的な誤差であるべき)と263KBのメモリを必要としますが、PooledListは<T>36usと0KBのメモリのみで十分です。




PooledDictionary<TKey、TValue>

ベンチマークで10000個の要素を辞書にループで加えます。 .NETネイティブのDictionary<TKey、TValue>は11msと13MBのメモリを必要とし、PooledDictionary<TKey、TValue>は7msと0MBのメモリで十分です。




プールドセット<T>

ベンチマークでハッシュコレクションをループし、10000個の要素を加えます。 .NETネイティブのHashSet<T>は5348msと2MBを必要としますが、PooledSetは<T>4723msと0MBのメモリで十分です。




プールドスタック<T>

ベンチマークでスタックをループして10000個の要素を追加します。 .NETネイティブのPooledStack<T>は1079msと2MBを必要としますが、PooledStackは<T>633msと0MBのメモリで十分です。




プールドキュー<T>

ベンチマークでループをループしてキューに10_0000個の要素を追加します。 .NETネイティブ<T>のPooledQueueは681msと1MBを必要としますが、PooledQueueは<T>408msと0MBのメモリで十分です。




シーンは手動でリリースされません

さらに、前述の通り、プールされたコレクションタイプはリリースされる必要がありますが、リリースされなくてもGCはリサイクルされるため問題ありません。


ベンチマークの結果は以下の通りです。



結論は上記のベンチマーク結果から導き出すことができます。

Pooled型コレクションを時間内に解放しても、GCはほとんどトリガーされずメモリを割り当てます。上記のグラフから見ると、割り当てられたメモリはわずか56バイトです。
たとえPooled型コレクションが解放されなくても、プールからメモリを割り当てるため、ReSize拡張操作中にメモリを再利用し、比較的高速なGC割り当てメモリ初期化ステップをスキップします。
最も遅いのは通常のコレクションタイプを使うことです。各ReSize拡張操作は新しいメモリ領域に適用し、GCは以前のメモリ領域も再利用する必要があります。


原理分析

もし私の前回のブログ記事を読んだなら、コレクションタイプの初期サイズを設定し、C#辞書の実装原理を分析してください。.NET BCL開発者はこれらの基本的なコレクションタイプの基礎データ構造を高性能ランダムアクセス用の配列として利用していることがわかります。例としてListを挙げましょう<T>。

追加要素を格納するための新しい配列を作成します。
配列に十分な空き容量がない場合は、拡張演算がトリガーされ、空間サイズの2倍を要求します。
コンストラクタコードは以下の通りで、直接作成された汎用配列であることがわかります:


ですので、メモリをプールしたい場合、クラスライブラリで新しいキーワードアプリケーションが使われる場所を変えるだけで、プールされたアプリケーションに切り替えられます。 ここで皆さんと共有します。 NET BCLはArrayPoolというタイプで、再利用可能な汎用インスタンスの配列リソースプールを提供します。これにより、GCへの負担を軽減し、頻繁な配列の作成や破棄時にパフォーマンスを向上させることができます。

Pooledタイプの基盤層はArrayPoolを使ってリソースプールを共有するもので、そのコンストラクタからデフォルトでArrayPoolを使用している<T>ことがわかります。 共有は配列オブジェクトを割り当てるためのもので、もちろん自分専用のArrayPoolを作成することもできます。


さらに、容量調整操作(拡張)を行う際には、古いアレイがスレッドプールに戻され、新しいアレイもプールから取得されます。

さらに、著者はSpanを使ってAdd and InsertなどのAPIを最適化し、より良いランダムアクセス性能を実現しています。 さらに、TryXXXシリーズAPIも追加され、より便利な方法で使えます。 例えば、<T>Listクラスは<T>PooledListと比べて最大170の修正があります。



概要

実際のオンライン使用では、ネイティブのコレクションタイプをPooledが提供するコレクションタイプに置き換えることができ、メモリ使用量とP95遅延の削減に非常に役立ちます。
また、リリースを忘れても、ネイティブのコレクションタイプを使うよりパフォーマンスはそれほど悪くありません。 もちろん、最良の習慣は時間内にリリースすることです。


翻訳元:ハイパーリンクのログインが見えます。




先の:RecyclableMemoryStreamは高性能な.NETストリーミングを提供します
次に:[実戦] サーバーはネットワーク速度をテストするためにLibreSpeedを構築します
2022年5月29日 17:12:36に投稿 |
覚えてみろ
2022年6月20日 09:09:22に投稿 |
ミックスを覚えましょう
免責事項:
Code Farmer Networkが発行するすべてのソフトウェア、プログラミング資料、記事は学習および研究目的のみを目的としています。 上記の内容は商業的または違法な目的で使用されてはならず、そうでなければ利用者はすべての結果を負うことになります。 このサイトの情報はインターネットからのものであり、著作権紛争はこのサイトとは関係ありません。 ダウンロード後24時間以内に上記の内容を完全にパソコンから削除してください。 もしこのプログラムを気に入ったら、正規のソフトウェアを支持し、登録を購入し、より良い本物のサービスを受けてください。 もし侵害があれば、メールでご連絡ください。

Mail To:help@itsvse.com