2

C# を使用してデータベースを作成しています。問題は、400 万近くのデータポイントがあり、データベースを完成させるのにかなりの時間がかかることです (おそらく数か月)。コードはこんな感じ。

int[,,,] Result1=new int[10,10,10,10];
int[,,,] Result2=new int[10,10,10,10];
int[,,,] Result3=new int[10,10,10,10];
int[,,,] Result4=new int[10,10,10,10];

for (int i=0;i<10;i++)
{
  for (int j=0;j<10;j++)
  {
    for (int k=0;k<10;k++)
    {
      for (int l=0;l<10;l++)
      {
        Result1[i,j,k,l]=myFunction1(i,j,k,l);
        Result2[i,j,k,l]=myFunction2(i,j,k,l);
        Result3[i,j,k,l]=myFunction3(i,j,k,l);
        Result4[i,j,k,l]=myFunction4(i,j,k,l);
      }
    }
  }
}

Result 配列のすべての要素は、互いに完全に独立しています。私のPCには8つのコアがあり、myFunctionメソッドごとにスレッドを作成しましたが、それでも多くの場合があるため、全体のプロセスには多くの時間がかかります. これをCPUではなくGPUで実行する方法があるかどうか疑問に思っています。私は以前にそれをしたことがなく、どのように機能するかわかりません。誰かがこれについて私を助けてくれれば幸いです。

4

3 に答える 3

1

はい、これらのシナリオの直感は、マルチスレッド/GPU を使用して高速化することです。しかし重要なことは、そのシナリオが並列計算に適しているかどうかを見極めることです。

これらのデータセットは互いに独立していると示唆しましたが、8 コアでマルチスレッド バージョンを実行すると、明らかな改善はありません。これは、潜在的な問題を示唆しています。データセットの独立性に関する記述が間違っているか、マルチ-スレッド化されたコードは最適化されていません。最初にコードを調整して改善を確認してから、これを GPU プラットフォームに移植する方法を探すことをお勧めします。

または、並列スレッドと GPU コアの両方を対象としたOPENCLをご覧ください。しかし重要なことは、あなたの質問が並列計算に本当に適しているかどうかを判断することです

于 2013-10-03T09:52:08.940 に答える
1

C++ AMP を使用してアプリケーションのこの部分を書き直し、.NET コードから呼び出すことを検討できます。詳細については、http://blogs.msdn.com/b/nativeconcurrency/archive/2012/08/30/learn-c-amp.aspxを参照してください。

ただし、表示するコードには、4,000,000 ではなく 40,000 のデータポイントがあります。

1 か月は約 260 万秒です。40,000 データポイントの場合、データポイントあたり 1 分以上になります。(たとえ 400 万のデータ ポイントがあったとしても、データ ポイントごとに 0.5 秒をはるかに超えます。) これらの関数が何をしているのかはわかりませんが、それほど長く実行する必要があるものがあることに驚かれることでしょう。 GPU で実行するのに適した候補です。

これらの関数で使用されているアルゴリズムを再検討して、最適化できるかどうかを確認する必要があるかもしれません。各データポイントを他のデータポイントとは独立して計算するには、考えを再考する必要があるかもしれません。他の結果が既にわかっている場合、1 つの結果をより効率的に計算することはできませんか?

アップデート:

この最後の発言で私が言いたいのは、計算が繰り返される可能性があるということです。たとえば、 によって実行される計算の一部がmyFunction1最初の 2 つのパラメーターのみに依存する場合、次のようにコードを再構築できます。

for (int i = 0; i < 10; i++)
{
  for (int j = 0; j < 10; j++)
  {
    var commonPartValue = commonPart(i, j);

    for (int k = 0; k < 10; k++)
    {
      for (int l = 0; l < 10; l++)
      {
        Result1[i, j, k, l] = myFunction1b(i, j, k, l, commonPartValue);
      }
    }
  }
}

正味の効果は、この「共通部分」を 1 回計算することです。これまでは 100 回計算していました。

もう 1 つのケースは、ゼロから計算する必要がある場合よりも、前の結果を使用してより効率的に結果を計算できる場合です。たとえば、n² は n * n として簡単に計算できますが、(n - 1)² が既にわかっている場合は、n² = (n - 1)² + 2 * n - 1 となります。整数演算では、これは a を置き換えることを意味します。シフトとデクリメントによる乗算。これはより高速です。

さて、あなたの問題がこれらの例のように単純だと主張しているわけではありませんが、より良いコンパイラや別のハードウェアを探す前に、まずこの種の最適化を探すべきだと言っています.

また、補足として、計算したものをRAMの配列ではなくディスクに保存すると仮定しています。結果が表示されるまで1か月も待ってから停電したくありません...

于 2013-10-03T09:49:39.320 に答える
0

あなたのコード例では、8 つのコアすべてを使用しているとは思いません。1 つだけです。以下は8つすべてを使用する必要があります。

 private void Para()
    {
        int[, , ,] Result1 = new int[10, 10, 10, 10];
        int[, , ,] Result2 = new int[10, 10, 10, 10];
        int[, , ,] Result3 = new int[10, 10, 10, 10];
        int[, , ,] Result4 = new int[10, 10, 10, 10];

        Parallel.For(0L, 10, i =>
        {
            Parallel.For(0L, 10, j =>
            {
                Parallel.For(0L, 10, k =>
                {
                    Parallel.For(0L, 10, l =>
                    {
                        Result1[i, j, k, l] = myFunction1(i, j, k, l);
                        Result2[i, j, k, l] = myFunction2(i, j, k, l);
                        Result3[i, j, k, l] = myFunction3(i, j, k, l);
                        Result4[i, j, k, l] = myFunction4(i, j, k, l);
                    });
                });
            });
        });
    }

これで十分でない場合は、Cudafyを見てください。C++ ですべての複雑な関数を書き直すよりも簡単になります。

于 2015-12-01T14:06:52.883 に答える