我对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
(或equivalent [...])作为表达式
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
表达式吗?
答案 0 :(得分:3)
好问题。您可以使用 forall
表达式(显式或[]
- "括号")以这种方式生成确定性结果,但{{{ 1}}表达式确实仍会导致并行执行。
像你这样的表达式有效地导致了拉链迭代,这种迭代被定义为相应的迭代将匹配。例如,在chapel中,似乎"整数阵列"操作如:
forall
等同于(提升)执行zippered var A, B, C: [1..10] real;
A = B + C;
循环:
forall
这两个表达式:
(a)指定并行执行,
(b)确保 var A, B, C: [1..10] real;
forall (a, b, c) in zip(A, B, C) do
a = b + c;
的相应元素,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;
和您提供的其他变体类似。
这是通过使用称为 leader-follower iterators 的概念在Chapel中完成的。这些最初是在PGAS 2011上发表的一篇名为User-Defined Parallel Zippered Iterators in Chapel slides are here的论文中描述的。它们也在教堂primer on parallel iterators中描述。