在C上使用OpenMP并行一段时间

我想在一段时间内做一个平行,像这样的somothing:

while(!End){ for(...;...;...) // the parallel for ... // serial code } 

for循环是while循环的唯一并行部分。 如果我这样做,我会有很多开销:

 cycles = 0; while(!End){ // 1k Million iterations aprox #pragma omp parallel for for(i=0;i<N;i++) // the parallel for with 256 iteration aprox if(time[i] == cycles){ if (wbusy[i]){ wbusy[i] = 0; wfinished[i] = 1; } } // serial code ++cycles; } 

for循环的每次迭代都是彼此独立的。

串行代码和并行代码之间存在依赖关系。

因此,通常人们不必过于担心将并行区域放入循环中,因为现代openmp实现对于使用线程团队之类的东西非常有效,只要循环中有很多工作就可以了。 但是,在这里,外部循环计数为~1e9,内部循环计数为~256 – 并且每次迭代完成的工作非常少 – 开销可能与正在完成的工作量相当或更差,性能将受到影响。

所以这之间会有明显的区别:

 cycles = 0; while(!End){ // 1k Million iterations aprox #pragma omp parallel for for(i=0;i 

还有这个:

 cycles = 0; #pragma omp parallel while(!End){ // 1k Million iterations aprox #pragma omp for for(i=0;i 

但实际上,不幸的是,每次迭代扫描时间数组都是(a)速度缓慢和(b)没有足够的工作来保持多个内核繁忙 - 这是内存密集型的。 有了几个线程,实际上你的性能会比串行更差,即使没有开销,也只是因为内存争用。 不可否认,您在此处发布的内容只是一个示例,而不是您的真实代码,但为什么不预先处理时间数组,以便您可以检查下一个任务何时可以更新:

 #include  #include  struct tasktime_t { long int time; int task; }; int stime_compare(const void *a, const void *b) { return ((struct tasktime_t *)a)->time - ((struct tasktime_t *)b)->time; } int main(int argc, char **argv) { const int n=256; const long int niters = 100000000l; long int time[n]; int wbusy[n]; int wfinished[n]; for (int i=0; i 

这比扫描方法的串行版本快〜5倍(并且比OpenMP版本快得多)。 即使您不断更新串行代码中的时间/ wbusy / wfinished数组,您也可以使用优先级队列跟踪其完成时间,每次更新需要O(ln(N))时间,而不是每次迭代扫描O( N)时间。