5

教堂减少目前忽略变量的初始值。这意味着这段代码

var x: int;
for i in 1..3 {
  forall j in 1..10 with (+ reduce x) {
    x += 1;
  }
}

writeln(x);

返回 10 而不是 30,正如该用户天真地认为的那样。虽然这种行为很好(并且它记录在减少子句的注释中 - 我只是没有认真考虑过),但事实证明,如果我想获得 30(通过在两个循环中累积),我需要实际上是手工计算的。我认为for循环也有一个reduce意图会非常优雅和对称......即我想写

var x: int;
for i in 1..3 with (+ reduce x) {
  forall j in 1..10 with (+ reduce x) {
    x += 1;
  }
}

writeln(x);

请注意,即使在求和数字的情况下,我也需要引入一个临时变量。对于像 max/min 这样的操作,需要更加小心。

是否有理由不支持reducefor 循环内部的意图?或者,是否有更惯用的(Chapel-rrific)方式来做到这一点?

更新:我想得越多,我提出的代码在外部for被替换为forall. 我认为问题在于变量是任务本地的而不是迭代本地的,因此减少只会发生在任务上。所以仍然需要一个单独的内部还原步骤。这将消除对临时变量的需要。

我认为更重要的问题是做这些嵌套减少的正确方法是什么......

4

1 回答 1

4

在我看来,这是 Chapel 减少意图设计中的一个疏忽。具体来说,虽然我认为每个任务在将归约变量的个人副本初始化为身份时忽略原始变量的值是适当的(正如您注意到当前所做的那样),但我相信任务的贡献应该合并回原始变量变量在并行循环结束时的值,而不是简单地覆盖原始值,因为它们相互结合。这将使您的原始尝试按您的预期工作,并且还将遵循 OpenMP 所做的,正如以下 C 示例所建议的那样,其结果为 35:

#include <stdio.h>
#include <omp.h>

int main(int argc, char* argv[]) {
  int tot = 5;
  for (int i=0; i<3; i++) {
  #pragma omp parallel for reduction(+:tot)
    for (int j=0; j<10; j++) {
      tot += 1;
    }
  }
  printf("tot is: %d\n", tot);
}

我建议在 Chapel GitHub 问题页面上提交一个提倡这种行为的错误/功能请求。

从 Chapel 1.15.0 开始,解决此问题的一种方法是在串行循环中手动进行缩减,如下所示:

config var tot: int = 5;

for i in 1..3 {
  var subtot: int;
  forall j in 1..10 with (+ reduce subtot) do
    subtot += 1;
  tot += subtot;
}

writeln("tot is: ", tot);
于 2017-07-16T15:20:51.577 回答