Выражение `forall`: параллельный или последовательный расчет?

Мое понимание 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 выражения в этом контексте?

1 ответ

Решение

Хороший вопрос. Вы правы, что с помощью forall выражения (явные или [] -"в скобках"), таким образом, дает детерминированные результаты, но 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, а также 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, под названием " Пользовательские параллельные итераторы на молнии в часовне", слайды которых здесь. Они также описаны в учебнике по часовням на параллельных итераторах.

Другие вопросы по тегам