MATLAB® поддерживает важное исключение, называемое сокращением, для правила, согласно которому итерации цикла должны быть независимыми. Переменная сокращения накапливает значение, которое зависит от всех итераций вместе, но не зависит от порядка итерации. MATLAB допускает переменные сокращения в parfor
-циклы.
Переменные сокращения появляются на обеих сторонах оператора назначения, например, любой из следующих, где expr
- выражение MATLAB.
X = X + expr | X = expr + X |
X = X - expr
| Смотрите Ассоциативность в Назначениях Сокращения в Требованиях для Назначений Сокращения |
X = X .* expr | X = expr .* X |
X = X * expr | X = expr * X |
X = X & expr | X = expr & X |
X = X | expr | X = expr | X |
X = [X, expr] | X = [expr, X] |
X = [X; expr] | X = [expr; X] |
X = min(X, expr) | X = min(expr, X) |
X = max(X, expr) | X = max(expr, X) |
X = union(X, expr) | X = union(expr, X) |
X = intersect(X, expr) | X = intersect(expr, X) |
Каждый из допустимых операторов, перечисленных в этой таблице, упоминается как назначение сокращения. По определению переменная сокращения может появляться только в присвоениях этого типа.
Общая форма назначения сокращения:
X = f(X, expr) | X = f(expr, X) |
В следующем примере показано типовое использование переменной сокращения X
.
X = 0; % Do some initialization of X parfor i = 1:n X = X + d(i); end
Этот цикл эквивалентен следующему, где вы вычисляете каждую d(i)
другой итерацией.
X = X + d(1) + ... + d(n)
В обычном for
-цикл, переменная X
получит свое значение либо перед входом в цикл, либо от предыдущей итерации цикла. Однако эта концепция не относится к parfor
-циклы.
В parfor
-цикл, значение X
никогда не передается от клиента к работникам или от работника к работнику. Скорее сложения d(i)
делаются в каждом рабочем, с i
диапазон по подмножеству 1:n
выполняются на этом работнике. Результаты затем передаются обратно клиенту, который добавляет частичные суммы работников в X
. Таким образом, рабочие делают некоторые сложения, а клиент - остальное.
Если ваш parfor
код не соответствует инструкциям и ограничениям, помеченным как Требуемый, вы получаете ошибку. MATLAB ловит некоторые из этих ошибок в то время, когда он читает код, и другие, когда он выполняет код. Эти ошибки помечены как Обязательные (статические) или Обязательные (динамические) соответственно. Инструкции, не вызывающие ошибок, помечены как Рекомендуемые. Можно использовать КОД MATLAB Analyzer, чтобы помочь parfor
- циклы соответствуют инструкциям.
Следующие потребности дополнительно определяют присвоения сокращения, связанные с заданной переменной.
Требуется (статический): Для любой переменной сокращения должна использоваться та же функция или операция сокращения во всех назначениях сокращения для этой переменной. |
parfor
-цикл слева недопустим, поскольку используется назначение сокращения +
в одном образце и [,]
в другом. parfor
-цикл справа действителен.
Инвалид | Действительный |
---|---|
parfor i = 1:n if testLevel(k) A = A + i; else A = [A, 4+i]; end % loop body continued end |
parfor i = 1:n if testLevel(k) A = A + i; else A = A + i + 5*k; end % loop body continued end |
Требуется (статический): Если назначение сокращения использует * , [,] , или [;] , затем X должен быть последовательно задан как первый или второй аргумент в каждом назначении сокращения. |
parfor
-loop слева недопустим, поскольку порядок элементов в конкатенации не согласован по всему циклу. parfor
-цикл справа действителен.
Инвалид | Действительный |
---|---|
parfor i = 1:n if testLevel(k) A = [A, 4+i]; else A = [r(i), A]; end % loop body continued end |
parfor i = 1:n if testLevel(k) A = [A, 4+i]; else A = [A, r(i)]; end % loop body continued end |
Требуется (статический): Вы не можете индексировать или индекс переменную сокращения. |
Код слева недопустим, так как он пытается индексировать a
и поэтому MATLAB не может классифицировать его как переменную сокращения. Чтобы исправить это, код справа использует неиндексированную переменную.
Инвалид | Действительный |
---|---|
a.x = 0 parfor i = 1:10 a.x = a.x + 1; end |
tmpx = 0 parfor i = 1:10 tmpx = tmpx + 1; end a.x = tmpx; |
Назначения на сокращение. В дополнение к конкретным формам назначения сокращения, перечисленным в таблице Переменные сокращения, единственная другая (и более общая) форма назначения сокращения является
X = f(X, expr) | X = f(expr, X) |
Требуемый (статический): f может быть функцией или переменной. Если f является переменной, тогда вы не можете изменить f в parfor тело (другими словами, это широковещательная переменная). |
Если f
является переменной, тогда для всех практических целей ее значение во время исполнения является указателем на функцию. Однако, пока правая сторона может быть оценена, полученное значение сохранено в X
.
parfor
-цикл слева не выполняется правильно, потому что оператор f = @times
причины f
классифицируется как временная переменная. Поэтому f
очищается в начале каждой итерации. parfor
-цикл справа правильно, потому что он не присваивает f
внутри цикла.
Инвалид | Действительный |
---|---|
f = @(x,k)x * k; parfor i = 1:n a = f(a,i); % loop body continued f = @times; % Affects f end |
f = @(x,k)x * k; parfor i = 1:n a = f(a,i); % loop body continued end |
Операторы &&
и ||
не указаны в таблице Переменные сокращения (Recovery Variables). Кроме &&
и ||
все матричные операции MATLAB имеют соответствующую функцию f
, таким образом u op v
эквивалентно f(u,v)
. Для &&
и ||
, такая функция не может быть записана, потому что u&&v
и u||v
может или не может оценить v
. Однако f(u,v)
всегда оценивает v
перед вызовом f
. Поэтому &&
и ||
исключены из таблицы допустимых сокращений для parfor
-цикл.
Каждое назначение сокращения имеет связанную функцию f
. Свойства f
которые гарантируют детерминированное поведение оператора parfor, обсуждаются в следующих разделах.
Ассоциативность в назначениях сокращения. Следующая практика рекомендуется для функции f
, как используется в определении переменной сокращения. Однако это правило не генерирует ошибку, если не соблюдается. Поэтому вы должны убедиться, что ваш код соответствует этой рекомендации.
Рекомендуемый: Получить детерминированное поведение parfor -циклы, функция редукции f должен быть ассоциативным. |
Чтобы быть ассоциативной, функция f
должен удовлетворять нижеследующим требованиям для всех a
, b
, и c
.
f(a,f(b,c)) = f(f(a,b),c)
Правила классификации для переменных, включая переменные редукции, являются чисто синтаксическими. Они не могут определить, f
ли Вы предоставили действительно ассоциативно или нет. Подразумевается ассоциативность, но если вы нарушаете это правило, каждое выполнение цикла может привести к различным ответам.
Примечание
Сложение математических вещественных чисел ассоциативно. Однако добавление чисел с плавающей запятой является только приблизительно ассоциативным. Различные казни этого parfor
оператор может привести к значениям X
с различными ошибками округления. Вы не можете избежать этой стоимости параллелизма.
Например, оператор слева дает 1, в то время как оператор справа возвращает 1 + eps
:
(1 + eps/2) + eps/2 1 + (eps/2 + eps/2)
Кроме оператора минус (-
), все специальные случаи, перечисленные в таблице в Переменных Сокращения, имеют соответствующую (приблизительно) ассоциативную функцию. MATLAB вычисляет X = X - expr
присвоения при помощи
X = X + (-expr)
. (Таким образом, технически функция для вычисления этого назначения сокращения plus
, не minus
.) Однако назначение X = expr - X
невозможно записать с помощью ассоциативной функции, что объясняет ее исключение из таблицы.
Коммутативность в заданиях на сокращение. Некоторые ассоциативные функции, включая +
, .*
, min
, и max
, intersect
, и union
, также являются коммутативными. То есть они удовлетворяют следующее для всех a
и b
.
f(a,b) = f(b,a)
Некоммутативные функции включают *
(поскольку умножение матрицы не коммутативно для матриц, в которых обе размерности имеют размер, больший единицы), [,]
, и [;]
. Некоммутативность является причиной того, что требуется согласованность в порядке аргументов к этим функциям. На практике более эффективный алгоритм возможен, когда функция коммутативна, а также ассоциативна, и parfor
оптимизирован для использования коммутативности.
Рекомендуемый: Кроме случаев * , [,] , и [;] , функция f сокращения должны быть коммутирующими. Если f не коммутирует, различные выполнения цикла могут привести к различным ответам. |
Нарушение ограничения коммутативности в функции, используемой для сокращения, может привести к неожиданному поведению, даже если оно не генерирует ошибку.
Если только f
является известной некоммутативной встроенной функцией, она принята коммутативной. В настоящее время нет способа задать определенную пользователем, некоммутативную функцию в parfor
.
Рекомендуемый: Перегрузка + , * , .* , [,] , или [;] должен быть ассоциативным, если он используется в назначении сокращения в parfor -цикл. |
Рекомендуемый: Перегрузка + , .* , union , или intersect должен быть коммутативным. |
Аналогичным образом, из-за особого обращения с X = X - expr
, рекомендуется следующее.
Рекомендуемый: Перегрузка оператора минус (- ) должен подчиняться математическому закону, что X - ( эквивалентно (X - . |
Предположим, что каждая итерация цикла выполняет некоторое вычисление, и вы заинтересованы в том, чтобы найти, какая итерация цикла создает максимальное значение. Это упражнение на сокращение делает накопление через несколько итераций цикла. Ваша функция сокращения должна сравнить результаты итерации, пока максимальное значение не может быть определено после сравнения всех итераций.
Сначала рассмотрим саму функцию редукции. Чтобы сравнить один результат итерации с другим, функция требует в качестве входа текущий результат и известный максимум от других итераций до сих пор. Каждый из двух входов является вектором, содержащим результаты итерации и число итераций.
function mc = comparemax(A, B) % Custom reduction function for 2-element vector input if A(1) >= B(1) % Compare the two input data values mc = A; % Return the vector with the larger result else mc = B; end end
Внутри цикла каждая итерация вызывает функцию сокращения (comparemax
), проходя в паре двухэлементных векторов:
Накопленный максимум и его индекс итерации, который является переменной сокращения cummax
Значение итерации и индекс
Если значение данных текущей итерации больше максимального в cummmax
функция возвращает вектор нового значения и его число итерации. В противном случае функция возвращает существующий максимум и число итераций.
Каждая итерация вызывает функцию сокращения comparemax
сравнение собственных данных [dat i]
к данным, уже накопленным в cummax
. Попробуйте следующий код для этого цикла.
% First element of cummax is maximum data value % Second element of cummax is where (iteration) maximum occurs cummax = [0 0]; % Initialize reduction variable parfor ii = 1:100 dat = rand(); % Simulate some actual computation cummax = comparemax(cummax, [dat ii]); end disp(cummax);
MATLAB классифицирует назначения формы X = expr op X
или X = X op expr
как операторы сокращения, когда они эквивалентны скобкам X = (expr) op X
или X = X op (expr)
соответственно. X
является переменной, op
является оператором сокращения, и expr
- выражение с одним или несколькими двоичными операторами сокращения. Следовательно, из-за правил приоритета оператора MATLAB, MATLAB может не классифицировать некоторые назначения формы X = expr op1 X op2 expr2 ...
, что цепные операторы, как операторы сокращения в parfor
-циклы.
В этом примере MATLAB классифицирует X
как переменная сокращения, поскольку назначение эквивалентно X = X + (1 * 2)
.
X = 0; parfor i=1:10 X = X + 1 * 2; end
В этом примере MATLAB классифицирует X
как временная переменная, поскольку назначение эквивалентно X = (X * 1) + 2
, не соответствует форме X = (expr) op X
или X = X op (expr)
.
X = 0; parfor i=1:10 X = X * 1 + 2; end
В качестве наилучшей практики используйте круглые скобки, чтобы явным образом задать приоритет оператора для назначений сокращений с цепочкой.