1

我对forall语句的理解是它们是并行执行的,而for语句是串行执行的。实际上,以下代码似乎证实了这种期望(即,仅用于forall线程的随机序列):

for i in 1..5 do writeln( i * 10 );
10
20
30
40
50

forall i in 1..5 do writeln( i * 10 );
10
50
20
30
40

另一方面,如果我在右侧使用forall(或等效的 [...] )作为表达式

var A = ( forall i in 1..5 do i * 10 );
var B = [ i in 1..5 ] i * 10;

var X = ( forall a in A do a );
var Y = [ a in A ] a;

var P = ( for i in 1..5 do i * 10 );  // for comparison

writeln( "A = ", A );
writeln( "B = ", B );
writeln( "X = ", X );
writeln( "Y = ", Y );
writeln( "P = ", P );

所有结果都变得相同(即从 10 到 50 排序):

A = 10 20 30 40 50
B = 10 20 30 40 50
X = 10 20 30 40 50
Y = 10 20 30 40 50
P = 10 20 30 40 50

这是否意味着forall赋值右侧的表达式总是串行执行?如果是这样,相应的 [...] 是否也等同for于该上下文中的表达式?

4

1 回答 1

3

好问题。以这种方式使用forall表达式(显式或[]-"bracketed" )生成确定性结果是正确的,但forall表达式仍然会导致并行执行。

像您这样的表达式有效地导致拉链迭代,其定义使得相应的迭代将匹配。例如,在中,看起来像“整个数组”的操作:

var A, B, C: [1..10] real;
A = B + C;

等同于(提升)拉链forall循环的执行:

var A, B, C: [1..10] real;
forall (a, b, c) in zip(A, B, C) do
  a = b + c;

这两个表达式:
(a)指定并行执行,
(b)确保A在循环体的每个实例中使用、B和数组的对应元素C(否则该语言不会很有用)。

举一个你的例子,

...B = [ i in 1..5 ] i * 10...

相当于:

forall (b, v) in zip(B, [i in 1..5] i * 10) do
  b = v;

或者:

forall (b, i) in zip(B, 1..5) do
  b = i * 10;

同样对于您提供的其他变体。

这是在 Chapel 中通过使用称为领导者-跟随者迭代器的概念来完成的。这些最初是在 PGAS 2011 上发表的一篇名为User-Defined Parallel Zippered Iterators in Chapel的论文中描述的,其幻灯片在这里。它们也在并行迭代器的 Chapel 入门中进行了描述。

于 2017-05-04T18:24:01.290 回答