10

私は C# で流体シミュレーションに取り組んでいます。各サイクルでは、空間内の離散点での流体の速度を計算する必要があります。その計算の一環として、いくつかの double[] 配列を保持するためのスクラッチ スペースとして数十キロバイトが必要です (配列の正確なサイズは入力データによって異なります)。配列は、それらを使用するメソッドの実行中にのみ必要であり、このようにスクラッチ スペースを必要とするいくつかの異なるメソッドがあります。

私が見ているように、スクラッチ配列を構築するためのいくつかの異なる解決策があります:

  1. メソッドが呼び出されるたびにヒープからメモリを取得するには、'new' を使用します。これは私が最初に行っていたことですが、ガベージ コレクターに大きな負担がかかり、1 秒に 1 ~ 2 回の数ミリ秒のスパイクは本当に厄介です。

  2. メソッドを呼び出すときに、スクラッチ配列をパラメーターとして渡します。問題は、これにより、ユーザーが適切なサイズ設定を含めてそれらを管理する必要があり、これは大きな苦痛です. また、API が変更されるため、多かれ少なかれスクラッチ メモリの使用が難しくなります。

  3. 安全でないコンテキストで stackalloc を使用して、プログラム スタックからスクラッチ メモリを割り当てます。これは問題なく機能しますが、/unsafe を指定してコンパイルし、コード全体に安全でないブロックを常に振りかける必要がありますが、これは避けたいと考えています。

  4. プログラムの起動時に一度プライベート配列を事前に割り当てます。入力データの一部を確認できるようになるまで、必要な配列のサイズが必ずしもわからないことを除けば、これで問題ありません。これらのプライベート変数のスコープを 1 つのメソッドだけに制限することはできないため、非常に面倒になり、名前空間が常に汚染されます。また、スクラッチ メモリを必要とするメソッドの数が増えると、スケーラビリティが低下します。これは、ごくわずかな時間しか使用されない大量のメモリを割り当てているためです。

  5. ある種の中央プールを作成し、プールからスクラッチ メモリ配列を割り当てます。これに関する主な問題は、中央のプールから動的にサイズ変更された配列を割り当てる簡単な方法が見つからないことです。開始オフセットと長さを使用して、基本的にすべてのスクラッチ メモリで 1 つの大きな配列を共有することもできますが、double[] を前提とする既存のコードが多数あります。そして、そのようなプールスレッドを安全にするように注意する必要があります.

...

同様の問題を経験した人はいますか?経験から得られるアドバイスや教訓はありますか?

4

2 に答える 2