如何通过循环将 OpenMP 线程拆分为子团队

How to split OpenMP threads into subteams over a loop

假设我有一个内部使用 #pragma omp parallel 的函数。

void do_heavy_work(double * input_array);

我现在想 do_heavy_work 上许多 input_arrays 因此:

void do_many_heavy_work(double ** input_arrays, int num_arrays)
{
    for (int i = 0; i < num_arrays; ++i)
    {
        do_heavy_work(input_arrays[i]);
    }
}

假设我有 N 个硬件线程。上面的实现将导致 num_arrays 调用 do_heavy_work 以串行方式发生,每个调用在内部使用所有 N 线程来执行它想要的任何并行操作。

现在假设当 num_arrays > 1 时,在这个外部循环上并行化实际上比在 do_heavy_work 中在内部并行化更有效。我现在有以下选择。

理想情况下,我希望 OpenMP 将其 OMP_NUM_THREADS 线程团队拆分为 num_arrays 个子团队,然后每个 do_heavy_work 可以在其分配的子团队中线程化(如果有的话)。

实现此目标的最简单方法是什么?

(为了讨论的目的,我们假设 num_arrays 不一定事先知道,而且我不能更改 do_heavy_work 本身的代码。代码应该适用于许多机器所以 N 应该可以自由指定。)

OMP_NUM_THREADS可以设置为一个列表,从而指定每一层嵌套的线程数。例如。 OMP_NUM_THREADS=10,4 将告知 OpenMP 运行时使用 10 个线程执行外部并行区域,每个嵌套区域将使用 4 个线程执行,总共最多同时执行 40 个 运行 个线程。

或者,您可以使用类似于以下代码的代码使您的程序自适应:

void do_many_heavy_work(double ** input_arrays, int num_arrays)
{
    #pragma omp parallel num_threads(num_arrays)
    {
        int nested_team_size = omp_get_max_threads() / num_arrays;
        omp_set_num_threads(nested_team_size);

        #pragma omp for
        for (int i = 0; i < num_arrays; ++i)
        {
            do_heavy_work(input_arrays[i]);
        }
    }
}

如果 OMP_NUM_THREADS 的值不能被 num_arrays 整除,此代码将不会使用所有可用线程。如果每个嵌套区域有不同数量的线程没问题(这可能导致某些数组的处理速度比其他数组快),请想出如何分配线程并相应地在每个线程中设置 nested_team_size 的想法。从并行区域内调用 omp_set_num_threads() 只会影响调用线程启动的嵌套区域,因此您可以有不同的嵌套团队大小。