Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 一种高效的阵列滤波并行算法_C_Multithreading_Concurrency_Parallel Processing_Openmp - Fatal编程技术网

C 一种高效的阵列滤波并行算法

C 一种高效的阵列滤波并行算法,c,multithreading,concurrency,parallel-processing,openmp,C,Multithreading,Concurrency,Parallel Processing,Openmp,给定一个非常大的数组,我只想选择符合某些条件的元素。我先验地知道要匹配的元素的数量。我当前的伪代码是: filter(list): out = list of predetermined size i = 0 for element in list if element matches condition out[i++] = element return out 在尝试并行化之前的算法时,我的天真方法是将i原子的增量作为OpenMP项目的一部分,因此使用p

给定一个非常大的数组,我只想选择符合某些条件的元素。我先验地知道要匹配的元素的数量。我当前的伪代码是:

filter(list):
  out = list of predetermined size
  i = 0
  for element in list
    if element matches condition
      out[i++] = element
  return out
在尝试并行化之前的算法时,我的天真方法是将i原子的增量作为OpenMP项目的一部分,因此使用pragma omp原子。但是,即使与串行实现相比,这种实现也会降低性能。有什么更有效的算法来实现这一点?为什么我会有如此严重的减速

评论中的信息:

我在OpenMP中使用C; 目前正在测试一百万个条目; 串行大约需要7秒,两个线程并行大约需要15秒; 输出数组的大小正好是问题的一半,等于找到数组的元素小于所述数组的中值; 我只测试了两个内核。 但是,与其他实现相比,此实现降低了性能 甚至是串行实现。还有什么更有效的算法 有什么办法来实现这一点

瓶颈是原子操作的开销,因此乍一看,更有效的算法应该是避免使用这种操作的算法。虽然这是可能的,但代码需要两步方法,例如,每个线程将在私有数组中保存找到的元素。在并行区域之后,主线程将收集每个线程找到的所有元素,并将它们合并到单个数组中

合并到单个阵列的第二部分也可以并行或使用SIMD指令

我创建了一个小代码来模拟您的伪代码:

#include <time.h>
#include <omp.h>

int main ()
{
  int array_size = 1000000;
  int *a = malloc(sizeof(int) * array_size); 
  int *out = malloc(sizeof(int) * array_size/2);
 
  for(int i = 0; i < array_size; i++)
      a[i] = i;   
 
  double start = omp_get_wtime();
  int i = 0;
  #pragma omp parallel for
  for (int n=0 ; n < array_size; ++n ){
      if(a[n] % 2 == 0){
         int tmp;
         #pragma omp atomic capture
         tmp = i++;
         out[tmp] = a[n]; 
      }
  }
  double end = omp_get_wtime();
  printf("%f\n",end-start);
  free(a);
  free(out);
  return 0;
}
因此,并行版本要慢得多,这是可以预期的,因为并行执行的工作根本不足以克服原子和并行的开销

我还测试了移除原子并离开竞赛条件,只是为了检查时间:

-> Sequential : 0.001597 (s)
-> 2 Threads  : 0.001283 (s)
-> 4 Threads  : 0.000720 (s)
因此,在没有原子线程的情况下,2个和4个线程的加速比分别约为1.2和2.2。因此,自然原子会造成巨大的开销。尽管如此,即使没有任何原子能,加速效果也不是很好。这是您可以从单独并行化代码中得到的最多的结果

根据您的实际代码,以及您的条件对计算的要求,即使使用我提到的第二种方法,您也可能无法获得很好的加速

以下评论中的有用注释:

即使它不会加速这个特定的例子,它也可能会加速 指出这样的问题通常是在 使用并行排他扫描算法/前缀的并行计算 求和以确定哪个线程从输出的哪个索引开始 大堆然后每个线程都有一个私有的输出索引,它正在递增 一个人不需要原子

在这种情况下,这种方法可能比@dreamcrashs解决方案慢 这是一种特殊情况,但更一般的情况是,每种情况都有专用数组 螺纹在确定其尺寸等方面可能非常棘手,尤其是在 您的输出大于每个输入元素所在的输入情况 不提供0或1个输出元素,但提供n个输出元素

-> Sequential : 0.001597 (s)
-> 2 Threads  : 0.001283 (s)
-> 4 Threads  : 0.000720 (s)