我开发了一个分布式内存MPI应用程序,它涉及网格的处理。现在我想使用OpenMP来应用共享内存技术(基本上使它成为混合 - 并行程序),看它是否可以变得更快或更高效。我在使用OpenMP时遇到了困难,尤其是嵌套for循环。我的应用程序涉及每隔半秒将网格打印到屏幕,但是当我将其与OpenMP并行化时,执行速度会慢10倍,或者根本不会。控制台屏幕滞后并使用随机/意外数据刷新自身。换句话说,它完全错了。看看下面的函数,它执行打印:
void display2dGrid(char** grid, int nrows, int ncolumns, int ngen)
{
//#pragma omp parallel
updateScreen();
int y, x;
//#pragma omp parallel shared(grid) // garbage
//#pragma omp parallel private(y) // garbage output!
//#pragma omp for
for (y = 0; y < nrows; y++) {
//#pragma omp parallel shared(grid) // nothing?
//#pragma omp parallel private(x) // 10 times slower!
for (x = 0; x < ncolumns; x++) {
printf("%c ", grid[y][x]);
}
printf("\n");
}
printf("Gen #%d\n", ngen);
fflush(stdout);
}
(updateScreen()只清除屏幕并再次从左上角写入。)
该函数仅由一个进程执行,这使其成为线程并行化的理想目标。正如你所看到的,我已经尝试了很多方法,其中一种比另一种更糟糕。最好的情况是,我每2秒获得半输出(因为它刷新非常缓慢)。最坏的情况我得到垃圾输出。
我将不胜感激任何帮助。有没有一个地方可以找到更多信息来正确并行化OpenMP循环?提前谢谢。
答案 0 :(得分:2)
该函数仅由一个进程执行,这使其成为线程并行化的理想目标。
实际上并非如此。您尝试并行化的功能是并行化的一个非常糟糕的目标。您示例中对printf
的调用需要按照特定的顺序发生,否则,您将获得有经验的垃圾结果(,因为您的网格元素将按照无意义的顺序打印)。实际上,你在并行化方面的尝试非常好,问题来自于函数本身是并行化的坏目标。
并行化程序时的加速来自于您在多个核心之间分配工作负载的事实。为了能够以最高效率实现这一目标,所述工作负载需要独立,或者至少尽可能少地共享状态,这不是这里的情况对printf
的调用需要按特定顺序进行。
当你尝试并行化一些内在顺序的工作时,你会失去更多时间synchronizing
你的工作者(你的openmp线程),而不是你通过平行工作本身而获得的(这就是你获得废话时间的原因)结果变得更好。)
另外,正如这个答案(https://stackoverflow.com/a/20089967/3909725)所暗示的,你不应该在每个循环中打印网格的内容(除非你正在调试),而是执行所有的计算,然后打印内容时你已经完成了你的最终目标,因为打印只对查看计算结果有用,并且只会减慢过程。
这是一个使用openmp对程序进行并行化以实现加速的非常基本的示例。这里为i
变量的每个值实现了一个虚拟(但很重)的计算。每个循环中的计算是完全独立的,并且不同的线程可以独立地实现它们的计算。对printf
的调用可以按任何顺序实现,因为它们只是提供信息。
原创(sequential.c)
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i,j;
double x=0;
for(i=0; i < 100; i++)
{
x = 100000 * fabs(cos(i*i));
for(j=0;j<100+i*20000;j++)
x += sqrt(sqrt(543*j)*fabs(sin(j)));
printf("Computed i=%2d [%g]\n",i,x);
}
}
并行化版本(parallel.c)
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int main()
{
int i,j;
double x=0;
#pragma omp parallel for
for(i=0; i < 100; i++)
{
/* Dummy heavy computation */
x = 100000 * fabs(cos(i*i));
#pragma omp parallel for reduction(+: x)
for(j=0;j<100+i*20000;j++)
x += sqrt(sqrt(543*j)*fabs(sin(j)));
printf("Thread %d computed i=%2d [%g]\n",omp_get_thread_num(),i,x);
}
}
可以在这里找到一个很好的openmp指南:http://bisqwit.iki.fi/story/howto/openmp/