免责声明:以下示例只是一个快速了解问题的虚拟示例。如果您正在考虑现实问题,请考虑任何动态编程。
问题: 我们有一个n * m矩阵,我们想要复制上一行中的元素,如下面的代码所示:
for (i = 1; i < n; i++)
for (j = 0; j < m; j++)
x[i][j] = x[i-1][j];
方法 外循环迭代必须按顺序执行,它们将按顺序执行。 内环可以并行化。我们希望最大限度地减少创建和杀死线程的开销,因此我们只想创建一次线程组,但是,这在OpenMP中似乎是一项不可能完成的任务。
#pragma omp parallel private(j)
{
for (i = 1; i < n; i++)
{
#pragma omp for scheduled(dynamic)
for (j = 0; j < m; j++)
x[i][j] = x[i-1][j];
}
}
当我们在外部循环上应用ordered
选项时,代码将以顺序方式执行,因此不会有性能提升。
我正在寻找上述场景的解决方案,即使我不得不使用一些解决方法。
我正在添加我的实际代码。这实际上比seq慢。版。请查看:
/* load input */
for (i = 1; i <= n; i++)
scanf ("%d %d", &in[i][W], &in[i][V]);
/* init */
for (i = 0; i <= wc; i++)
a[0][i] = 0;
/* compute */
#pragma omp parallel private(i,w)
{
for(i = 1; i <= n; ++i) // 1 000 000
{
j=i%2;
jn = j == 1 ? 0 : 1;
#pragma omp for
for(w = 0; w <= in[i][W]; w++) // 1000
a[j][w] = a[jn][w];
#pragma omp for
for(w = in[i][W]+1; w <= wc; w++) // 350 000
a[j][w] = max(a[jn][w], in[i][V] + a[jn][w-in[i][W]]);
}
}
至于测量,我使用的是这样的东西:
double t;
t = omp_get_wtime();
// ...
t = omp_get_wtime() - t;
答案 0 :(得分:1)
总结OpenMP中针对这种特殊情况的并行化:这是不值得的。
<强>为什么吗
内循环中的操作很简单。代码是使用-O3
编译的,因此max()
调用可能已替换为函数体的代码。
隐式屏障的开销可能足够高,以补偿性能增益,并且总体开销足够高,使得并行代码甚至比顺序代码更慢。
我也发现,这种结构没有真正的性能提升:
#pragma omp parallel private(i,j)
{
for (i = 1; i < n; i++)
{
#pragma omp for
for (j = 0; j < m; j++)
x[i][j] = x[i-1][j];
}
}
因为它的表现类似于这个
for (i = 1; i < n; i++)
{
#pragma omp parallel for private(j)
for (j = 0; j < m; j++)
x[i][j] = x[i-1][j];
}
感谢GCC libgomp
中的内置线程重用,根据这篇文章:http://bisqwit.iki.fi/story/howto/openmp/
由于外部循环不能被并行化(没有ordered
选项),因此看起来无法使用OpenMP显着提高相关程序的性能。如果有人觉得我做错了,而且有可能,我很乐意看到并测试解决方案。