教堂减少目前忽略变量的初始值。这意味着这段代码
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);
请注意,即使在汇总数字的情况下,我也需要引入一个临时变量。对于最大/最小的操作,需要更加小心。
是否有理由不在for循环中支持reduce
意图?或者,有没有更惯用的(Chapel-rrific)方法呢?
更新:我越是想到这一点,我所提议的代码在外部for
被forall
取代的情况下不起作用并不明显。我认为问题在于变量是任务本地的而不是迭代本地的,因此减少只会发生在任务上。因此,仍然需要一个单独的内部缩减步骤。这将删除需要一个临时变量。
我认为更为重要的问题是,进行这些嵌套缩减的正确方法是......
答案 0 :(得分:5)
在我看来,这是对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);
}
我建议在教堂GitHub issues page上提交一个提倡此行为的错误/功能请求。
从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);