OpenMP for 循环并行性问题



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

#pragma omp parallel for schedule(static, 2) reduction(+:tot_ext) 
for (int i = 0;i<num_pos;i++) {
if (fscanf(stdin,"%lu,%lun", &from, &to) != 2) {
fprintf(stderr, "Cannot read correctly intervals filen");
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 秒

我的问题是:为什么差异这么小?

OpenMP 设置一个线程池,在发生拆分时,根据情况在这些线程(部分(之间分配工作。

分配工作、启动工作线程并在最后将它们全部连接起来涉及大量成本。

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

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

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

  • 自给自足
  • 不使用同步呼叫
  • 本身就是实质性的作品

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

第一句话

引自 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 必须在omp critical部分中(我不知道编译器是否自动执行此操作。

所以malloc部分是顺序的。

最后备注:

tot_ext减少了,因此您不能期望在这里实现完全的可扩展性。

结论

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

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

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

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

谢谢大家的回答。根据您的建议,我设法清理了一下我的代码,以便现在:)

最新更新