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 Анализатор, чтобы помочь 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
- цикл слева не допустим, потому что порядок пунктов в конкатенации не сопоставим в цикле. 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 |
Операторы &&
и ||
не перечислены в таблице в Переменных Сокращения. За исключением &&
и ||
, все операции над матрицей 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 - цикл. |
Рекомендуемый: перегрузка + , .* объединение , или intersect должно быть коммутативным. |
Точно так же из-за специального режима X = X - expr
, следующее рекомендуется.
Рекомендуемый: перегрузка минус оператор (- ) должен подчиниться математическому закону что X - ( эквивалентно (X - . |
В этом примере вы запускаете расчеты в цикле и храните максимальное значение и соответствующий индекс цикла. Можно использовать собственную функцию сокращения и parfor
- цикл, чтобы ускорить ваш код. В каждой итерации сохраните значение расчета и индекса цикла в векторе-строке с 2 элементами. Используйте пользовательскую функцию сокращения, чтобы сравнить этот вектор с сохраненным вектором. Если значение от расчета больше хранимой суммы, замените старый вектор на новый вектор.
Создайте функцию сокращения valueAndIndex
. Функция берет два вектора в качестве входных параметров: valueAndIndexA
и valueAndIndexB
. Каждый вектор содержит значение и индекс. Функция сокращения valueAndIndex
возвращает вектор с самым большим значением (первый элемент).
function v = compareValue(valueAndIndexA, valueAndIndexB) valueA = valueAndIndexA(1); valueB = valueAndIndexB(1); if valueA > valueB v = valueAndIndexA; else v = valueAndIndexB; end end
Создайте вектор 1 на 2 всех нулей, maxValueAndIndex
.
maxValueAndIndex = [0 0];
parfor
- цикл. В каждой итерации используйте rand
создавать случайную стоимость. Затем используйте функцию сокращения valueAndIndex
сравнить maxValueAndIndex
к случайному значению и индексу цикла. Когда вы храните результат как maxValueAndIndex
, вы используете maxValueAndIndex
как переменная сокращения.parfor ii = 1:100 % Simulate some actual computation thisValueAndIndex = [rand() ii]; % Compare value maxValueAndIndex = compareValue(maxValueAndIndex, thisValueAndIndex); end
После parfor
- цикл закончил запускаться, переменная maxValueAndIndex
сокращения доступно на клиенте. Первым элементом является самое большое случайное значение, вычисленное в
parfor
- цикл и второй элемент являются соответствующим индексом цикла.
maxValueAndIndex
maxValueAndIndex = 0.9706 89.0000
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
Как лучшая практика, используйте круглые скобки, чтобы явным образом задать приоритет оператора для цепочечных присвоений сокращения.