我是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秒。
我的问题是:为什么差异如此之小?
答案 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相对不切实际(因为您将 没有看到加速)
这也适用于标准输出
因此,最好的情况fscanf
和fwrite
部分将是顺序的,最坏的情况将是一团糟。
第二句话
为
•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(),我能够测量操作本身的时间。结果如下:
谢谢大家的回答。根据您的建议,我设法整理了一下代码,以使现在的代码效率更高:)