配列プール

Dec 15 2022
現在、配列を使用することはめったにありません。ほとんどの場合、List<T> を使用します。これは、より多くの機能を提供し、内部の配列に基づいています。

現在、配列を使用することはめったにありません。ほとんどの場合、List<T> を使用します。これは、より多くの機能を提供し、内部の配列に基づいています。しかし、多くのオブジェクトを処理する際にパフォーマンスが重要になる場合があります。

私が驚いたのは、単純な配列が List の 2 倍効率的であり、それでも ArrayPool で最適化できることです。

この記事では、コード例とパフォーマンスのベンチマークを使用して ArrayPool を使用する方法を紹介します。

コード リポジトリ

アレイプールとは

ArrayPool は、配列型のインスタンスを再利用できるリソース プールです。これを使用して、バッファー (配列) をレンタルおよび返却できます。メモリとGARBAGE COLLECTORを大量に消費する配列を頻繁に作成および破棄する場合のパフォーマンスが向上します。このクラスはスレッドセーフであり、同時に使用できます。プールに戻るときに、コンテンツを消去するかどうかを選択できます。クリアには時間がかかりますが、状況によっては毎回空の配列を取得する必要がある場合があります。

それを使用する方法

プール メモリから配列にアクセスするには、2 つの方法があります。

最初の最も簡単な方法は、ArrayPool共有プロパティを使用することです。

ArrayPool<T>.Shared

プールのデフォルトの実装が得られます。さまざまなサイズの配列が含まれています。要求したよりも大きな配列を返すことができますが、それよりも小さいことはありません。共有プールは配列を再利用する便利な方法ですが、より優れたものもあります。

より効率的な方法は、create メソッドを使用してプールを初期化することです。

ArrayPool<T>.Create()

ArrayPool<T>.Create(int maxArrayLength, int maxArraysPerBucket)

Create メソッドは、プールのカスタム インスタンスを返します。別の場所からアクセスして再利用するには、キャッシュする必要があります。パラメーター化された方法は、最高のパフォーマンスを達成するのに役立ちます。maxArrayLength以下の長さの配列をサイズ maxArraysPerBucket のバケットにグループ化するインスタンスを作成します。

C# の配列プーリングを利用して、割り当てを減らし、アプリケーションのパフォーマンスを向上させます。

基準

これは簡単なテストです。新しいアレイを作成する場合とプールからレンタルする場合の違いを比較します。いずれの場合も、1_000_000 個の要素のコレクションを反復処理します。また、ベンチマークに List<T> を含めて、配列のパフォーマンス上の利点を示します。

コード リポジトリ

基準

結論

私が最も驚いたのは、速度とメモリ使用量の点で、単純な配列が List の 2 倍効率的であることです。また、ArrayPool を使用して最適化することもできます。プールを使用することは明らかに行く方法です。

標準配列とプールからの配列の使用には顕著な時間差があります。時間差は、毎回新しい配列を作成するときにメモリを割り当てるのに必要な時間です。もちろん、メモリ割り当てにも違いがあります。ArrayPool は新しいメモリを割り当てる必要はありません。同じブロックを再利用します。

警告として、「キャッシュなしのカスタム プール」を追加したので、毎回新しいプールを作成するとどうなるかを確認できます。毎回新しい配列を作成するのと基本的には同じことです。

この単純な例では、共有 ArrayPool とカスタム ArrayPool のパフォーマンスの違いを示すのは困難です。サイズの異なる多数の配列が使用されている場合に顕著になります。

ArrayPool の使用が常に最も便利であるとは限りませんが、必要に応じて計算能力を大幅に節約できる場合があります。