【问题标题】:Why am I getting worst performance with a private dynamic array为什么使用私有动态数组时性能最差
【发布时间】:2021-04-04 05:54:51
【问题描述】:

我想使用 OpenMP 来并行化一个 for-loop 计算器,它执行以下操作:

B = (int*)malloc(sizeof(int) * N); //N is known
for(i=0;i<500000;i++)
{  
    for(j=0;j<M;j++) B[j]=i+j;  //M is different from N, but M <= N;
    some operations on B which produce a variable L;
    printf("%d\n",L);    
}

我不需要重新分配 B,因为它将为每次迭代相应地定义其值。这些操作将只使用 B[0] 到 B[M-1]。这样可以节省大量B的分配和初始化时间。

为了使用openmp,我把代码改成这样:

#pragma omp parallel num_threads(32) private(i,j,B,M,L)
{
  B = (int*)malloc(sizeof(int) * N); //N is known
  #pragma omp parallel for 
  for(i=0;i<500000;i++)
  {  
      for(j=0;j<M;j++) B[j]=i+j;  //M is different from N, but M <= N;
      some operations on B which produce a variable L;
      printf("%d\n",L);    
  }
}

与第一个相比,它的运行速度非常慢,因为它为每个线程创建了一个新的 B 数组(所以 500000 次)。 有没有办法使用 openmp 来避免这种情况?

【问题讨论】:

    标签: c++ c multithreading performance openmp


    【解决方案1】:

    主要问题是循环的迭代没有按照您的意愿分配给线程。因为您再次将子句parallel 添加到#pragma omp for,并假设您已禁用嵌套并行性,默认情况下,在外部parallel 区域中创建的每个线程都将“按顺序”执行其中的代码该区域,即:

      #pragma omp parallel for 
      for(i=0;i<500000;i++){  
          ...
      }
    

    因此,每个线程将执行您打算并行化的内部循环的所有500000 迭代。因此,移除并行性并为顺序代码增加额外的开销(例如线程创建)。尽管如此,只需删除第二个parallel 子句即可轻松解决此问题,即:

    #pragma omp parallel num_threads(32) private(i,j,B,M,L)
    {
        B = (int*)malloc(sizeof(int) * N); //N is known
        #pragma omp for 
        for(i=0;i<500000;i++){  
          ...   
        }
    }
    

    取决于执行代码的设置(例如, 是否在 NUMA 架构中,如果使用的 malloc 函数是(或不是)线程感知内存分配器,除其他外)可能建议对您的并行区域进行概要分析,以检查将2D 数组的分配移动到该区域之外是否值得(或不值得)。替代版本的示例:

    int total_threads = 32;
    int** B = malloc(sizeof(*int) * total_threads);
    for(int i = 0; i < total_threads; i++){
        B[i] = malloc(N * sizeof(int));
    }
    
    #pragma omp parallel num_threads(32) private(i,j,M,L)
    {
      int threadID = omp_get_thread_num();
      #pragma omp for 
      for(i=0;i<500000;i++)
      {  
          for(j=0;j<M;j++) 
              B[threadID][j]=i+j;  //M is different from N, but M <= N;
          some operations on B which produce a variable L;
          printf("%d\n",L);    
      }
    }
    // you might need to reduce all the values from all threads
    // to main thread array.
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 2016-04-21
      • 2017-05-24
      • 2014-01-21
      • 2012-03-29
      • 1970-01-01
      • 2010-11-27
      相关资源
      最近更新 更多