0

N-Body シミュレーションを書いています。計算を簡単にするために、空間全体を多数の均一なサイズの領域に分割しました。

各ボディについて、同じ領域内の他のすべてのボディの力を計算し、他の領域については、質量と距離を一緒に集計するので、実行する作業が少なくなります。

と があり、この反復で総質量を合計するものList<Region>Region定義します。public void Index()

Space.Tick()関数には 2 つのバリアントがあります。

public void Tick()
{
  foreach (Region r in Regions)
    r.Index();
}

これは非常に速いです。20x20x20 = 8000 領域でそれぞれ 100 体 = 合計 800000 体の場合、これを行うのに約 0.1 秒しかかかりません。CPU グラフは、私のクアッドコアで 25% の使用率を示しています。これはまさに私が予想していたものです。

今、私はこのマルチスレッドバリアントを書きます:

public void Tick()
{
  Thread[] threads = new Thread[Environment.ProcessorCount];

  foreach (Region r in Regions)
    while (true)
    {
      bool queued = false;

      for (int i = 0; i < threads.Length; i++)
        if (threads[i] == null || !threads[i].IsAlive)
        {
          Region s = r;
          threads[i] = new Thread(s.Index);
          threads[i].Start();
          queued = true;
          break;
        }

      if (queued)
        break;
    }
}

明らかでない場合の簡単な説明:threads私の CPU の場合、4 の配列です。4x から始まりますnull。領域ごとに、4 つThreadのオブジェクトすべて ( の可能性がありますnull) をループします。nullいずれかまたはそうでないものを見つけたら、それとそれをIsAliveキューに入れます。リージョンがインデックス作成を開始したことを確認できるように設定しました。Index()RegionStart()queuedtrue

このコードには約 7 秒かかります。それは70倍遅いです。スレッドの設定、空いているスレッドの検索などに多少のオーバーヘッドがあることは理解していますが、少なくとも何らかのパフォーマンスの向上は期待できます。

私は何を間違っていますか?

4

1 に答える 1

3

PLINQ を試してみませんか?

Regions.AsParallel().ForAll(x=>x.Index());

PLINQ は通常、私にとって超高速であり、環境に応じてスケーリングされます.Parallel でない場合は、シングル スレッドを実行します。

したがって、多次元配列を関数に入れる必要がある場合は、次のようにするだけです。

 Regions.AsParallel().Cast<Region>().ForAll(x=>x.Index());
于 2012-11-14T02:18:53.813 に答える