2

OpenMP 'parallel' 构造和 'SIMD' 构造(4.0 版中新增)定义了归约子句,它告诉编译器对哪个变量执行归约以及归约运算符是什么。但是为什么编译器需要程序员告诉它这些信息呢?例如,GCC 具有识别缩减的能力,而无需程序员的任何帮助(请参阅此处此处)。有没有指定减少子句就不能并发的循环示例?

4

1 回答 1

3

减少是一种简单的机制,可以通过删除同步点来提高并行应用程序的性能,并以内存视图的宽松一致性为代价。从以下示例中应该可以立即清楚地看到明确具有归约子句的需要:

想象一下,您有一个代码对无序的NUM_ITEMS项目集合进行搜索,目标是找到所有符合给定条件的项目并将它们收集到一个数组matches中,并计算这些项目的某些属性的总和。找到项目的顺序无关紧要。序列号可能是这样的:

int num_matches = 0;
int prop_sum = 0;

for (i = 0; i < NUM_ITEMS; i++)
{
   if (criteria(item[i]))
   {
      match[num_matches] = item[i];
      num_matches++;
      prop_sum += item[i]->some_property;
   }
}

num_matches和都是prop_sum变量,其值随着循环的进行而累积。但是这两个变量具有完全不同的语义。虽然prop_sum可以将其计算为部分和的总和,num_matches但不能因为它用作输出数组中的索引。prop_sum是减少的典型候选者num_matches,但不仅可以减少,而且还必须利用显式同步结构来防止数据竞争和不同的线程覆盖 的相同元素match

int num_matches = 0;
int prop_sum = 0;

#pragma omp parallel for reduction(+:prop_sum)
for (i = 0; i < NUM_ITEMS; i++)
{
   if (criteria(item[i]))
   {
      #pragma omp critical(update_matches)
      {
          match[num_matches] = item[i];
          num_matches++;
      }
      prop_sum += item[i]->some_property;
   }
}

尽管您可能会争辩说编译器可能足够聪明,可以注意到使用的方式num_matches并自动生成原子增量,但 OpenMP 的目标是在平台和编译器供应商之间可移植。这意味着,如果您编写的 OpenMP 程序符合标准并且可以在一个编译器上正常编译和工作,那么它也应该可以在其他编译器上正常编译和工作。该标准由许多不同的供应商编写,并不是每个供应商都有这种超级智能的数据依赖发现机制。此外,当涉及编译单元外部的数据时,很难进行可靠的检测。

reduction不是必需品——它只是一种便利。您可以实现自己的缩减,例如使用原子增量,这对于您的平台可能是最佳的,但在其他不提供有效原子增量的平台上可能远非最佳。另一方面,预计每个编译器都将生成代码,reduction以针对给定目标平台以最佳方式实现该子句。

于 2013-05-23T13:44:43.957 回答