GPU上数组元素的并行计算

时间:2013-10-03 08:57:45

标签: c# parallel-processing gpu

我正在使用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方法创建了一个线程,但是整个过程只需要很多,因为有很多情况。我想知道是否有任何方法可以在GPU而不是CPU上运行它。我以前没有这样做,我不知道它会如何工作。如果有人能帮助我,我很感激。

3 个答案:

答案 0 :(得分:1)

您可以考虑使用C ++ AMP重写应用程序的这一部分,并从.NET代码中调用它。有关详细信息,请参阅http://blogs.msdn.com/b/nativeconcurrency/archive/2012/08/30/learn-c-amp.aspx

但是,在您显示的代码中,有40,000个数据点,而不是4,000,000个。

一个月大约有260万秒。对于40,000个数据点,每个数据点可以提供超过一分钟的数据点。 (即使你确实有400万个数据点,每个数据点仍然会超过半秒。)我不知道这些函数在做什么,但我会惊讶于那些需要长时间运行的东西是在GPU上运行的好选择。

也许您需要重新审视这些功能中使用的算法,看看它们是否可以进行优化。您甚至可能需要重新考虑您的想法,以独立于其他数据点计算每个数据点。如果您已经了解其他一些结果,您确定无法更有效地计算一个结果吗?

更新:

我最后一句话的意思是,可能会重复计算。例如,如果由myFunction1完成的部分计算仅取决于前两个参数,则可以按如下方式重构代码:

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);
      }
    }
  }
}

净效应是你曾经计算过一次这个“共同部分”,你曾经这样做了一百次。

另一种情况是,您可以使用之前的结果更有效地计算结果,而不是必须从头开始。例如,n²可以很容易地计算为n * n,但如果你知道(n - 1)²,那么n²=(n - 1)²+ 2 * n - 1.在整数算术中,这意味着你替换一个乘以一个移位和一个递减,这是更快。

现在,我并没有声称你的问题就像这些例子一样简单,但我说你应该在寻找更好的编译器或不同的硬件之前首先寻找这些优化。

另外,作为旁注:我假设您将计算的内容存储在磁盘上,而不是存储在RAM中的数组中。我不想等待一个月的结果显示,然后停电......

答案 1 :(得分:1)

是的,这些场景的直觉是使用多线程/甚至GPU来加速。但重要的是弄清楚场景是否适合并行计算。

正如您所建议的那样,这些数据集彼此独立,但是当您在8个核心上运行多线程版本时,没有明显的改进:这表明存在潜在问题:您对数据集独立性的陈述是错误的还是您的实现多线程代码的优化未得到优化。我建议你首先调整代码以查看改进,然后寻找将其移植到GPU平台表格的方法。

或者您可以查看针对并行线程/ GPU核心的 OPENCL 。 但重要的是弄清楚你的问题是否真的适合并行计算

答案 2 :(得分:0)

我不认为您的代码示例使用了所有八个核心 - 只有一个核心。 以下应该使用全部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);
                    });
                });
            });
        });
    }

如果这还不够have a look at Cudafy,那么比用C ++重写所有复杂函数更容易。