4

私は研究ツールとして C# を使用しており、最適化などの CPU 集中型のタスクを頻繁に実行する必要があります。理論的には、コードをマルチスレッド化することでパフォーマンスを大幅に改善できるはずですが、実際には、ワークステーションで使用可能なコア数と同じ数のスレッドを使用すると、通常、CPU はまだ 25 でしか実行されていません。 %-最大の 50%。newほとんどのスレッドはステートメントの実行を待機するため、コードを中断してすべてのスレッドが何を行っているかを確認すると、メモリ割り当てがボトルネックになっていることが強く示唆されます。

解決策の 1 つは、すべてのコードを再設計して、メモリ効率を大幅に向上させることですが、それは大きく、時間のかかる作業になります。ただし、ワークステーションには十分なメモリがあるので、さまざまなスレッドを設定して、それぞれが独自のプライベート メモリ プールを使用できるようにすることで、この問題を回避できるかどうか疑問に思っています。もちろん、一部のオブジェクトはすべてのスレッド間で公開する必要があります。そうしないと、各スレッドのタスクを指定したり、結果を収集したりすることができなくなります。

この種のアプローチが C# で可能かどうかは誰にもわかりません。

4

3 に答える 3

6

メモリ割り当てのボトルネックがある場合は、次のことを行う必要があります。

  1. 「オブジェクトプール」を使用します(@MartinJamesが言ったように)。アプリケーションの起動時に、オブジェクト プールを初期化します。オブジェクト プールにより、ヒープ割り当てのパフォーマンスが向上するはずです。

  2. スタックの割り当てはヒープよりもはるかに高速であるため、構造体 (または任意の値の型) をローカル変数として使用します。

  3. 暗黙的なメモリ割り当てを回避します。たとえば、アイテムを に追加すると、次のようになりますList<>

    Count がすでに Capacity に等しい場合、List の容量は内部配列を自動的に再割り当てすることによって増加し、既存の要素は新しい要素が追加される前に新しい配列にコピーされます (ソース MSDN)。

  4. ボクシングは避けてください。それは非常に高価です:

    単純な割り当てに関連して、ボックス化とボックス化解除は計算コストの高いプロセスです。値型がボックス化されている場合、新しいオブジェクトを割り当てて構築する必要があります。程度は低いですが、ボックス化解除に必要なキャストも計算コストが高くなります。(ソース MSDN)

  5. 変数をキャプチャするラムダ式は避けてください (キャプチャされた変数に対して新しいオブジェクトが作成されるため)

于 2013-08-06T20:09:12.073 に答える
1

これは、私がサーバーで行っていることと似ています - 頻繁に使用されるクラスにはオブジェクト プールを使用します (ただし、C# ではありません)。

C# では、BlockingCollection を使用できると思います。そこから T と Take() オブジェクトのロードを事前に入力し、それらを使用してから Add() で返します。

これは、多数の大きなオブジェクト (サーバー データ バッファーなど) や、複雑で長い ctors/dtors (http レシーバー/パーサー コンポーネントなど) を持つオブジェクトでうまく機能します。 NET では)、オフ/オン キューは、それらを継続的に作成し、後で GC でそれらを破棄するよりもはるかに高速です。

注: このようなプール キューからポップされたオブジェクトは、以前に使用された可能性があり、明示的な初期化が必要になる場合があります。

于 2013-08-06T08:18:47.363 に答える
0

特に C# や .NET の問題ではありません。CPU コアが最適に動作するには、すべてのデータが CPU キャッシュにある必要があります。特定のデータが CPU キャッシュにない場合、キャッシュ障害が発生し、データがメモリからキャッシュにフェッチされるまで CPU はアイドル状態になります。

メモリ内データが断片化しすぎると、キャッシュ障害の可能性が高くなります。

CLR がヒープ割り当てを行う方法は、CPU キャッシュに最適です。メモリ割り当てを自分で処理して同じパフォーマンスを達成できる可能性は低いです。

于 2013-08-06T07:20:34.513 に答える