首页 > 解决方案 > 性能下降:分叉代码与。openmp 代码

问题描述

我有使用 fork() 的并行代码来“读取灰度图像并将其转换为二进制”。我使用 openmp 将代码转换为多线程代码。但是,我注意到与使用 fork 的代码相比,openmp 代码的性能较差。我最初怀疑这可能是 openmp 开销,因此直接尝试使用 pthreads。但我注意到同样的模式。与分叉代码相比,pthread 代码的执行时间也更长。(注意:pthreads 比 openmp 略好几微秒)

以下是相同条件下的执行时间。

+-----------------+-------------+--------------+
| No. of children | using fork  | using openmp |
+-----------------+-------------+--------------+
|              20 | 1.3         | 1.6          |
|              50 | 1.6         | 2.2          |
|             100 | 2.7         | 3.7          |
|             150 | 3.7         | 5.3          |
|             200 | 4.5         | 7.1          |
|             250 | 6.0         | 9.0          |
|             600 | 15.2        | 22.06        |
+-----------------+-------------+--------------+

编辑:添加代码。编译器:gcc-4.8.5,CPU 数量:256

由以下 2 个代码调用的函数:

void imgProcess(char* nam){
  Pix *pixg = pixRead(nam);      
  Pix *pixb, *pixgray;
  pixgray = pixConvertRGBToGray(pixg,0.33,0.33,0.34);
  pixSauvolaBinarizeTiled(pixgray, 8, 0.34, 1, 1, NULL, &pixb); 
  pixDestroy(&pixg);    
  pixDestroy(&pixb);    
}

使用 fork() 的代码:

int main() { 

  char prefix[60]="/root/Test/img_";  
  struct timespec i1, i2;
  long long elapsed;
  clock_gettime(CLOCK_MONOTONIC, &i1);  

  int count = 200;
  for(int i=0; i<count; i++){   
      if(fork() == 0){
        char filname[60];
        sprintf(filname,"%s%d%s",prefix,i,".jpg"); 
        imgProcess(filname);
        exit(0);
      }
  }    

  for(int i=0; i<count; i++)
    wait(NULL); 


  clock_gettime(CLOCK_MONOTONIC, &i2);
  elapsed = i2.tv_sec*1000000000LL + i2.tv_nsec - i1.tv_sec*1000000000LL - i1.tv_nsec;
  cout<<"Total : "<<(double)elapsed/1000000000LL<<endl;

  return 0;
}

使用 openmp 的代码:

int main() { 
  int count = 200;
  omp_set_num_threads(count);

  char prefix[60]="/root/Test/img_";  
  struct timespec i1, i2;
  long long elapsed;
  clock_gettime(CLOCK_MONOTONIC, &i1);

  #pragma omp parallel for
  for(int j=0;j<count;j++){ 
      char filname[60];
      sprintf(filname,"%s%d%s",prefix,j,".jpg");         
      imgProcess(filname);
  }


  clock_gettime(CLOCK_MONOTONIC, &i2);
  elapsed = i2.tv_sec*1000000000LL + i2.tv_nsec - i1.tv_sec*1000000000LL - i1.tv_nsec;
  cout<<"Total : "<<(double)elapsed/1000000000LL<<endl;

  return 0;
}

即使我接受,超出某个数量,forks() 会比线程快,根据这个线程,我仍然认为它们不会快几秒钟。

附加信息:我做了两个小测试。

  1. 第一个测试:我现在没有将上面的 imgProcess() 函数作为一个工作单元,而是将一个简单的“循环浪费时间”作为并行作业的一个工作单元,并注意到 openmp 和分叉代码的时间几乎相似。
  2. 第二个测试:我的并行作业的工作单元不是使用上面的 imgProcess() 函数作为工作单元,而是使用 C++ 流“读取文本文件”。在这种情况下,openmp 代码和分叉代码的时序也相似。

    +---------+-------+--------+
    | threads | fork  | openmp |
    +---------+-------+--------+
    |      20 | 0.018 | 0.008  |
    |      50 | 0.04  | 0.01   |
    |     100 | 0.08  | 0.04   |
    |     150 | 0.11  | 0.03   |
    |     200 | 0.16  | 0.07   |
    |     250 | 0.19  | 0.08   |
    +---------+-------+--------+
    

问题:

  1. 我的印象是线程和分叉应该具有相似的运行时。找出为什么多线程代码在不同情况下表现不同的任何想法?
  2. 到目前为止,我只是用线程替换了 fork() 部分。实际上有一个并行化灰度到二进制图像转换算法本身的范围,我还没有这样做。看到上面的时间,我觉得继续并行化算法可能没有用。你有什么建议?你觉得并行化可能有用吗?

标签: multithreadingperformanceforkopenmp

解决方案


推荐阅读