使用OpenMP进行归纳:获取OpenMP中并行化for循环的范围值

时间:2013-10-15 10:00:32

标签: openmp

我想知道一种方法来获取OpenMP with C ++中并行for循环中给定线程的值范围。例如,在下面的代码中,我想知道每个线程在每个线程的循环中使用的第一个值。

#pragma omp parallel for schedule(static)
for(int i=0; i<n; i++) 

让我举个例子说明为什么我可能想要这些价值观。我们假设我想用一个计数数字的总和来填充一个数组。计数数之和的封闭形式解是n*(n+1)/2。要使用OpenMP执行此操作,我可以这样做:

#pragma omp parallel for schedule(static)
for(int i=0; i<n; i++) {    
    a[i] = i*(i+1)/2;
}

但是,我怀疑获得计数数字总和的更快方法是不使用每次迭代的闭合形式解(具有正方形),而是记住每次迭代的总和,如下所示:

int cnt = 0;
for(int i=0; i<n; i++) {
    cnt += i;
    a[i] = cnt;
}

但是我可以想到用OpenMP执行此操作的唯一方法是明确定义范围值,如下所示:

#pragma omp parallel
{
    const int ithread = omp_get_thread_num();
    const int nthreads = omp_get_num_threads();
    const int start = ithread*n/nthreads;
    const int finish = (ithread+1)*n/nthreads;

    int cnt = 0;
    int offset = (start-1)*(start)/2;
    for(int i=start; i<finish; i++) {
        cnt += i;
        a[i] = cnt + offset;
    }
}

如果我可以从#pragma omp parallel for schedule(static)获取起始值,那么我就不必定义start, finish, ithread, and nthreads

编辑: 阅读Agner Fog's Optimizing C++手册后,我意识到我所做的就是感应。 他举了一个使用归纳法来更有效地计算多项式值的例子。以下是他手册中的一些例子

没有归纳:

// Example 8.23a. Loop to make table of polynomial
const double A = 1.1, B = 2.2, C = 3.3; // Polynomial coefficients
double Table[100]; // Table
int x; // Loop counter
for (x = 0; x < 100; x++) {
    Table[x] = A*x*x + B*x + C; // Calculate polynomial

感应:

// Example 8.23b. Calculate polynomial with induction variables
const double A = 1.1, B = 2.2, C = 3.3; // Polynomial coefficients
double Table[100]; // Table
int x; // Loop counter
const double A2 = A + A; // = 2*A
double Y = C; // = A*x*x + B*x + C
double Z = A + B; // = Delta Y
for (x = 0; x < 100; x++) {
    Table[x] = Y; // Store result
    Y += Z; // Update induction variable Y
    Z += A2; // Update induction variable Z
}

要使用OpenMP执行此操作,我需要获取每个块的起始值。使用OpenMP执行此操作的唯一方法是手动定义块。

2 个答案:

答案 0 :(得分:1)

这是一个扩展的评论而不是答案......

没有OpenMP例程或预定义变量来获取每个线程将执行的i(在您的情况下)的值范围。你必须按照你所概述的方式写一些东西来自己获取这些数字。

但在你做之前,请停下来思考一下。所有额外的代码,以及编写和维护它的努力,只是为了避免每次迭代一次乘法!即使你让你的代码工作,我怀疑你看到的任何加速都值得付出努力。更糟糕的是,只要您想使用与static不同的时间表,就必须重新进行索引计算;对于许多其他调度选项,一个线程执行的迭代无论如何都不会是一个简单的范围。

您正在编程,不仅仅是OpenMP,而且可能是并行编程。可以在不考虑运行时可用数量的情况下分发给线程的程序,或者运行时系统如何分割工作以及在任务之间没有依赖关系的程序是并行化的理想选择。它们通常为大量线程提供良好的可伸缩性,而无需大量的程序员工作。

您已经拥有的封闭式解决方案就是您所需要的。顺其自然。针对谷物的编程将(不可避免地会争辩)产生更复杂的代码,这些代码难以维护,并且很少会产生并行加速以补偿其成本。

答案 1 :(得分:0)

可能无法做到这一点。即使您可以获得每个线程的范围,例如start,您希望将其注入到这样的单个for循环中?

#pragma omp parallel for schedule(static)
for(int i=0; i<n; i++) {    
    a[i] = ...
}

omp parallel for通常假设迭代之间没有依赖关系。如果添加cnt等依赖项,则可能不应使用此指令。