OpenMP:使用较少的线程或较短的最大可用线程是否更好?

时间:2018-01-13 01:34:34

标签: c++ multithreading parallel-processing openmp

我正在为优化任务运行一些C ++代码,我正在尝试使用OpenMP并行化它。我尝试在两个循环上使用#pragma omp parallel for,但很快意识到它不起作用,所以我想设置一个条件来决定是否并行化外部或内部循环,具体取决于有多少外部迭代。 / p>

以下是代码:

std::vector<Sol> seeds; // vector with initial solutions
std::vector<Sol> sols (N_OUTER*N_INNER); // vector for output solutions
int N_OUTER; // typically 1-8
int N_INNER;  // typically > 100
int PAR_THRESH; // this is the parameter I am interested in setting

#pragma omp parallel for if (N_OUTER >= PAR_THRESH)
for (int outer = 0; outer < N_OUTER; ++outer){
    #pragma omp parallel for if (N_OUTER < PAR_THRESH)
    for (int inner = 0; inner < N_INNER; ++inner){
        sols[outer*N_INNER + inner] = solve(seeds[outer]);
    }
}

这可以很好地决定哪个循环(内部或外部)并行化;但是,我正在尝试确定PAR_THRESH的最佳值。

我的直觉说如果N_OUTER为1,那么它不应该与外部循环并行,如果N_OUTER大于可用的线程数,那么外部循环应该是要平行化的那个;因为它使用最大可用线程,并且线程尽可能长。我的问题是N_OUTER是2还是3(4是可用的线程数)。

运行比较长的并行的2或3个线程是否更好;但是没有用完所有可用的线程?或者最好是串行运行2或3个外循环,同时利用内循环的最大线程数?

或者是否有一种权衡取舍,也许2次外循环迭代可能会浪费线程,但如果有3次外循环迭代,那么拥有更长的线程是有益的,尽管事实上一个线程仍未使用?

修改

已编辑的代码,用N_ITER替换N_INNER两个地方

1 个答案:

答案 0 :(得分:1)

没有太多使用OpenMP的经验,但我找到了类似collapse指令的内容:

https://software.intel.com/en-us/articles/openmp-loop-collapse-directive

Understanding the collapse clause in openmp

当内循环迭代次数不同时,似乎更合适。

-

另一方面:

在我看来,solve(...)是无副作用的。似乎N_ITER也是N_INNER。

目前你计算解决N_INNER * N_OUTER次。 虽然减少不会降低O符号的复杂性,但假设它具有非常大的常数因子 - 它应该节省大量时间。您无法使用collapse缓存结果,因此这可能会更好:

std::vector<Sol> sols_tmp (N_INNER);
#pragma omp parallel for
for (int i = 0; i < N_OUTER; ++i) { 
    sols_tmp[i] = solve(seeds[i]);
}

这只计算N_OUTER次。

因为solve为每一行返回相同的值:

#pragma omp parallel for
for (int i = 0; i < N_OUTER*N_INNER; ++i) {
    sols[i] = sols_tmp[i/N_INNER];
}

当然,如果并行化适合于那些循环,则必须进行测量。