OpenMP for循环并行性问题

时间:2018-10-16 11:33:09

标签: c++ openmp

我是OpenMP的新手,我想将for循环迭代划分为相等的块。到目前为止,我已经做到了:

#pragma omp parallel for schedule(static, 2) reduction(+:tot_ext) 
for (int i = 0;i<num_pos;i++) {

    if (fscanf(stdin,"%lu,%lu\n", &from, &to) != 2) {
        fprintf(stderr, "Cannot read correctly intervals file\n");
        exit(1);
    }

    time = getTime();
    text = (uchar*)malloc(to-from+2);

    readlen = sdsl::extract(csa, from, to, text);
    tot_time += (getTime() - time);

    tot_ext += readlen;

    if (Verbose) {
        fwrite(&from,sizeof(ulong),1,stdout);
        fwrite(&readlen,sizeof(ulong),1,stdout);
        fwrite(text,sizeof(uchar),readlen, stdout);
    }

    free(text);
}
  • 在一个内核上运行此查询所需的时间:2.72秒。

  • 在两个内核上运行此查询所花费的时间:2.64秒。

我的问题是:为什么差异如此之小?

4 个答案:

答案 0 :(得分:3)

OpenMP设置了一个线程池,并在拆分发生时,根据情况将工作分配给了(某些)线程。

分配工作,启动工作线程并最终将它们全部加入都需要花费大量成本。

除非每次循环迭代中都要完成大量工作,否则管理线程的开销成本可能远远超过其好处-尝试并行处理一个小循环比运行仅慢许多倍。它可以在单个处理器上运行,可以利用寄存器重用和本地核心缓存的优势。

如果调用某些系统函数(例如fwrite),它们可能也会强制线程之间进行同步,这会影响结果。

为了进行更公平的测试,请尝试进行以下工作:

  • 独立的
  • 请勿使用同步通话
  • 本身就是重要的工作

这将使您以更适用的方式测试并行性的可能优势。

答案 1 :(得分:2)

第一句话

OpenMP论坛(http://forum.openmp.org/forum/viewtopic.php?f=3&t=764)的报价

  

通常,从多个线程读取和写入文件是   除非底层操作系统或I / O系统是一个好主意,   真正支持它(通常称为并行I / O)。
  很多时候I / O   例程可用于从同一文件中的单独文件读取/写入   时间。那是因为每个I / O实例都保留了自己的数据区   告诉它从哪一行读取或写入。但是,当你   有多个线程尝试读取/写入您需要的同一文件   I / O系统为所有线程为该文件保留一个数据区。   这不是通常要做的事情,因此最终需要序列化(或   以某种方式锁定)I / O。当然,这会拖慢整个过程,并且   因此使得并行化I / O相对不切实际(因为您将   没有看到加速)

这也适用于标准输出

因此,最好的情况fscanffwrite部分将是顺序的,最坏的情况将是一团糟。

第二句话

  

•OpenMP线程共享一个可执行文件,全局内存和堆   (新的malloc)

因此,malloc必须位于omp critical节中(我不知道编译器是否自动执行此操作。)

所以malloc部分是连续的。

最后评论:

tot_ext减少了,因此您不能期望此处具有完全的可伸缩性。

结论

最后,真正并行处理的唯一部分是readlen = sdsl::extract(csa, from, to, text);,如果它不是最昂贵的操作,则您的时间安排是一致的。

答案 2 :(得分:1)

仅关于性能,而不是线程安全性-此测试的问题是您使用的是stdin,getTime,malloc,fwrite,free等。这些功能大多数都在内部通过操作系统调用实现,从而导致不可预料的延迟和同步。尽量避免这样的电话,您将获得更好的结果。

答案 3 :(得分:1)

问题解决了。为什么我的测量时间不好的主要问题是因为使用了getTime()方法,该方法测量每个线程上的时间花费并进行总结。使用omp_get_wtime(),我能够测量操作本身的时间。结果如下:

  • 1个线程:2.72秒
  • 2个线程:1.41秒
  • 3个线程:0.94秒
  • 4个线程:0.73秒

谢谢大家的回答。根据您的建议,我设法整理了一下代码,以使现在的代码效率更高:)