C#メモリキャプチャ/空き速度

この問題が発生しました:データファイルを処理する必要があります。 ファイルは約1 MBのセクションに分割され、各セクションには約100,000個のレコードがパック形式で格納されます。レコード数はセクションごとに異なり、各ヘッダーに記録されます。 処理中、セクションはアンパックされ、各レコードは20個の整数になります。 処理のために、現在のアンパックされたセクションといくつかの以前のセクション(5〜10前後、しかしそれよりも多い-それがいくつであるかは事前にはわかりません)を保存する必要があります。 問題は、セクションを展開するためのメモリの割り当て方法です。

問題を解決するために必要なフレームワーク内のプロジェクトは、VS 2008のC#で記述されています(他の言語からの挿入を使用することは強く推奨されません)。 そして、いつものように、より速く処理する必要があります。
発生する最初の問題は、展開するためにアレイプールを整理する必要があるかどうか、または新しいセクションごとにアレイを再度キャプチャできるかどうかです。 2番目の質問は、この配列の構造をどのようにするかです。長さ8 MBの線形配列で作業するか、配列を小さな断片に分割して、たとえば配列の配列を編成します。 2番目のケースでは、これらの断片の長さはどうなりますか。

私はいくつかのオブジェクトを取りました:

2次元配列の数値MとNは、M * N = 40,000,000(20セクションのメモリに対応)になるように選択されました。
各オブジェクトについて、作成+充填+読み取り(オブジェクトが忘れられた後)の平均時間を測定し、制御については、充填+読み取り(オブジェクトが1回だけ作成された)時間を測定しました。 時間は、オブジェクトの処理された要素ごとにナノ秒単位で測定されました。 測定は2回実行されました:1つのプロセッサコアで作業するとき、および4つのコアを並列で作業するとき(2番目のケースでは、4で費やされた時間は増加しませんでした。つまり、結果は、通常、シングルコアの場合よりも短くなります)。

結果は次のようになります。
MXN8000x50002000x200001000x40000100x40000010x40000001x40000000
int [] []8.34 / 7.308.34 / 7.024.08 / 2.693.76 / 2.553.62 / 2.583.63 / 2.78
int [] []、R + W2.57 / 1.602.64 / 1.602.22 / 1.042.20 / 1.002.18 / 1.002.09 / 1.03
int []、フル1.94 / 1.041.85 / 0.963.4 / 1.583.44 / 2.693.60 / 3.633.60 / 2.78
int []、R + W1.58 / 0.461.56 / 0.471.56 / 0.471.57 / 0.631.83 / 0.932.00 / 1.05
リスト16.30 / 9.1419.16 / 19.0021.69 / 35.1753.8 / 85.65145/130
リスト、読む2.32 / 0.602.29 / 0.612.31 / 1.126.4 / 2.587.2 / 3.67
リスト<int>8.95 / 4.2111.06 / 4.7411.98 / 5.0311.85 / 6.3811.85 / 6.9813.71 / 8.10
リスト<int>、読み取り2.95 / 0.882.96 / 0.922.96 / 0.922.96 / 0.923.13 / 1.054.13 / 1.65

1つと4つのコアに対して、各セルに2回記録されます。
このプレートから何を抽出できますか? まず、メモリを直線的にキャプチャするのにかかる時間は、配列の長さに依存することがわかります。160MBの長さの1つの線形配列は、1.6 MBの長さの配列よりも100倍長くキャプチャされます。 次に、1つのアレイを短時間でキャプチャする場合、短いアレイには利点があります:キャプチャには0.3 ns /ワード、長いアレイのキャプチャには1.8 ns /ワード(3行目と4行目の違い)が必要です。 これは、88 KB未満のオブジェクトは別の高速プールから取得されるというよく引用される主張を裏付けています。 しかし、配列が多数ある場合、状況は逆になります。長い配列の場合は約1.5 ns /ワード、短い配列の場合は5.8 ns /ワード-ほぼ4倍になります。 したがって、多次元配列が短時間必要な場合は、短い内部配列で段階的に配列しないでください。別のオプションを探すことをお勧めします。 たとえば、1次元配列を取得してインデックスを読み取ります。

さらに、システムがリストの実装をまったく好まなかったことは明らかです。リストの長さが100万に近づくと、1つのアイテムを作成する時間が、短いリストに比べて約6倍に増加しました。

私のタスクに最適なのは、明らかに、長い配列(アンパックされたセクションごとに1つ)をキャプチャすることです-毎回配列をキャプチャする場合。 1600セクションの長さのファイル(これは一般的なサイズです)の場合、時間損失は1.5 * 2 * 1.6 = 5秒になります。 確かに、処理オプションの1つを完了するのに11秒しかかかりません(不要なメモリキャプチャなし)が、考えなければならないことがあります。他の処理はより長く複雑になります。 可能な限りメモリを再利用し続け、動的メモリを乱用しないようにする必要がある可能性があります。 しかし、そうではないかもしれません。

Source: https://habr.com/ru/post/J137066/


All Articles