OpenMP:使用较少的长线程更好,还是使用最大可用的短线程更好?

Posted

技术标签:

【中文标题】OpenMP:使用较少的长线程更好,还是使用最大可用的短线程更好?【英文标题】:OpenMP: Is it better to use fewer threads that are long, or maximum available threads that are short? 【发布时间】:2018-01-13 01:34:33 【问题描述】:

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

代码如下:

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】:

对 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];

当然必须衡量并行化是否适合这些循环。

【讨论】:

你是正确的N_ITER = N_INNER,这是一个错字对不起。就您的其余答案而言,谢谢,我不知道collapse 子句,但看起来它可能是一个很好的解决方案。关于solve(),它是一种随机优化算法,将seeds[i] 作为初始解,但对于相同的种子,不一定返回相同的值。这就是为什么我需要两个循环,一个循环遍历种子解决方案,内部循环基于这些种子生成N_INNER 解决方案。但是感谢有关collapse 的提示,我会调查一下!

以上是关于OpenMP:使用较少的长线程更好,还是使用最大可用的短线程更好?的主要内容,如果未能解决你的问题,请参考以下文章

如果我使用异步,不应该使用更少的线程数吗?

sql 别名允许您通过用较短的名称(通常是单个字符)替换表的长名称来键入较少的字符。第8行显示

使用英特尔 OpenMP 找到最佳线程数:只有 1 个线程比许多线程有更好的结果

使用 openMP 和 openACC 的多线程多 GPU 计算

C++ openmp并行程序在多核linux上如何最大化使用cpu

如何获得在整个程序执行期间可能创建的最大 OpenMP 线程数?