繁体   English   中英

OpenMP:嵌套并行化有什么好处?

[英]OpenMP: What is the benefit of nesting parallelizations?

据我了解, #pragma omp parallel及其变体基本上在多个并发线程中执行以下块,这与CPU的数量相对应。 当具有嵌套并行化时-并行for并行for,并行函数中的并行函数等-内部并行会发生什么?

我是OpenMP的新手,我想到的情况可能很简单-将向量与矩阵相乘。 这是通过两个嵌套的for循环完成的。 假设CPU的数量小于向量中元素的数量,尝试并行运行内部循环是否有任何好处? 线程总数是否会大于CPU数量,还是会顺序执行内部循环?

(1)OpenMP中的嵌套并行性: http : //docs.oracle.com/cd/E19205-01/819-5270/aewbc/index.html

您需要通过设置OMP_NESTEDomp_set_nested来打开嵌套并行性,因为许多实现默认情况下都会关闭此功能,即使某些实现也不完全支持嵌套并行性。 如果打开了,则每当您遇到parallel for OpenMP时,OpenMP就会创建OMP_NUM_THREADS定义的线程数。 因此,如果是2级并行,则线程总数将为N ^ 2,其中N = OMP_NUM_THREADS

这种嵌套的并行性将导致超额订购(即,繁忙线程的数量大于内核的数量),这可能会降低速度。 在一个极端的情况下,递归调用嵌套并行性,线程可能会膨胀(例如,创建1000s线程),而计算机只是浪费时间进行上下文切换。 在这种情况下,您可以通过设置omp_set_dynamic动态控制线程数。

(2)矩阵向量乘法的示例:代码如下:

// Input:  A(N by M), B(M by 1)
// Output: C(N by 1)
for (int i = 0; i < N; ++i)
  for (int j = 0; j < M; ++j)
     C[i] += A[i][j] * B[j];

通常,由于线程的派生/连接开销,并行化内部循环而可能实现外部循环是不好的。 (尽管许多OpenMP实现预先创建线程,但仍需要一些将任务分派到线程并在parallel-for结束时调用隐式屏障)

您关心的是N <#CPU的情况。 是的,对,在这​​种情况下,加速将受到N的限制,而让嵌套的并行性无疑会带来好处。

但是,如果N足够大,则代码将导致超额订购。 我只是在考虑以下解决方案:

  • 更改循环结构,以便仅存在1级循环。 (看起来可行)
  • 专门化代码:如果N小,则执行嵌套并行性,否则不要这样做。
  • 带有omp_set_dynamic嵌套并行性。 但是,请确保omp_set_dynamic如何控制线程数和线程活动。 实现可能会有所不同。

对于像稠密线性代数这样的东西,其中所有潜在的并行性已经在一个宽广的for循环中已经被放置在一个地方,则您不需要嵌套的并行性-如果您确实想避免出现(例如)非常窄的情况如果矩阵的前导维数可能小于内核数,那么您所需要做的就是折叠指令,该指令可以将多个循环合为一个平面。

嵌套并行处理是针对那些并行处理没有一次全部暴露的情况-假设您想同时进行2个函数评估,每个评估都可以有效地利用4个内核,而您拥有8个内核系统。 您可以在并行部分中调用该函数,并且在函数定义内还有一个附加函数,例如,并行。

在外部级别,使用NUM_THREADS(num_groups)子句设置要使用的线程数。 如果您的外循环的计数为N,并且处理器或内核的数量为num_cores,请使用num_groups = min(N,num_cores)。 在内部级别,您需要为每个线程组设置子线程数,以使子线程总数等于核心数。 因此,如果num_cores = 8,N = 4,则num_groups =4。在较低级别,每个子线程应使用2个线程(由于2 + 2 + 2 + 2 = 8),因此请使用NUM_THREADS(2)子句。 您可以将子线程的数量收集到一个数组中,每个外部区域线程一个元素(带有num_groups个元素)。

该策略始终充分利用您的内核。 当N <num_cores时,会发生嵌套的并行化。 当N> = num_cores时,子线程计数数组包含全1,因此内部循环实际上是串行的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM