parfor- ПетлиMATLAB ® Coder™ классифицирует переменные внутри parfor-закольцовывание в одну из категорий в следующей таблице. Он не поддерживает переменные, которые он не может классифицировать. Если parfor-loop содержит переменные, которые не могут быть однозначно классифицированы, или, если переменная нарушает ограничения категории, parfor-loop генерирует ошибку.
| Классификация | Описание |
|---|---|
| Петля | Служит индексом цикла для массивов |
| Нарезанный | Массив, сегменты которого обрабатываются различными итерациями цикла |
| Передача | Переменная, определенная перед циклом, значение которой используется внутри цикла, но не назначено внутри него |
| Сокращение | Накапливает значение в итерациях цикла независимо от порядка итераций |
| Временный | Переменная, созданная внутри цикла, но в отличие от разделенных или сокращенных переменных, недоступная вне цикла |
Каждая из этих классификаций переменных появляется в этом фрагменте кода:
a=0;
c=pi;
z=0;
r=rand(1,10);
parfor i=1:10
a=i; % 'a' is a temporary variable
z=z+i; % 'z' is a reduction variable
b(i)=r(i); % 'b' is a sliced output variable;
% 'r' a sliced input variable
if i<=c % 'c' is a broadcast variable
d=2*a; % 'd' is a temporary variable
end
endРазделенная переменная - это переменная, значение которой может быть разбито на сегменты или фрагменты, которые затем обрабатываются отдельно различными потоками. Каждая итерация цикла работает на другом срезе массива.
В следующем примере фрагмент A состоит из одного элемента этого массива:
parfor i = 1:length(A) B(i) = f(A(i)); end
Переменная в parfor-луп разрезается, если он имеет следующие характеристики:
Тип индексирования первого уровня - первый уровень индексирования состоит из скобок, ().
Список фиксированных индексов - в скобках первого уровня список индексов одинаков для всех вхождений данной переменной.
Форма индексирования - в списке индексов переменной ровно один индекс включает переменную цикла.
Форма массива - при назначении разделенной переменной правая сторона назначения не [] или '' (эти операторы указывают на удаление элементов).
Тип индексирования первого уровня. Для разделенной переменной первый уровень индексирования заключен в круглые скобки, (). Например, A(...). При ссылке на переменную с помощью точечной нотации A.x, переменная не разделена.
Переменная A слева не нарезан; переменная A справа нарезается:
A.q(i,12) A(i,12).q
Список фиксированных индексов. В скобках первого уровня индексирования разделенной переменной список индексов одинаков для всех вхождений данной переменной.
Переменная B слева не разрезан, потому что B индексируется по i и i+1 в разных местах. Переменная B справа разрезается.
parfor i = 1:10 B(i) = B(i+1) + 1; end |
parfor i = 1:10 B(i+1) = B(i+1) + 1; end |
Форма индексирования. В списке индексов для разделенной переменной один индекс имеет вид i, i+k, i-k, k+i, или k-i.
i является переменной цикла.
k является константой или простой (неиндексированной) переменной.
Каждый другой индекс является константой, простой переменной, двоеточием или end.
При использовании других переменных вместе с переменной цикла для индексирования массива невозможно задать эти переменные внутри цикла. Эти переменные являются постоянными в течение выполнения всего parfor заявление. Невозможно объединить переменную цикла с самим собой для формирования индексного выражения.
В следующих примерах: i - переменная цикла, j и k являются неиндексированными переменными.
| Переменная A не разрезается | Переменная A разрезается |
|---|---|
A(i+f(k),j,:,3) A(i,20:30,end) A(i,:,s.field1) |
A(i+k,j,:,3) A(i,:,end) A(i,:,k) |
Форма массива. Разделенная переменная должна сохранять постоянную форму. В следующих примерах переменная A не разрезан:
A(i,:) = []; A(end + 1) = i;
Широковещательная переменная - это переменная, отличная от переменной цикла, или разделенная переменная, которая не изменяется внутри цикла.
Понижающая переменная накапливает значение, которое зависит от всех итераций вместе, но не зависит от порядка итераций.
В этом примере показан parfor-loop, использующий скалярное понижающее назначение. Используется переменная сокращения x для накопления суммы 10 итерации цикла. Порядок выполнения итераций в потоках не имеет значения.
x = 0; parfor i = 1:10 x = x + i; end x
Где 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 = min(X, expr) | X = min(expr, X) |
X = max(X, expr) | X = max(expr, X) |
X=f(X, expr)Функция f должна быть определяемой пользователем функцией. | X = f(expr, X)См. разделы Назначение сокращения, ассоциативность и коммутативность функций сокращения. |
Каждая из разрешенных инструкций называется назначением сокращения. Переменная сокращения может отображаться только в присвоениях этого типа.
В следующем примере показано типичное использование переменной сокращения X:
X = ...; % Do some initialization of X
parfor i = 1:n
X = X + d(i);
end
Этот цикл эквивалентен следующему, где каждый d(i) рассчитывается другой итерацией:
X = X + d(1) + ... + d(n)
Если цикл был обычным for-loop, переменная X в каждой итерации получит свое значение либо перед входом в цикл, либо из предыдущей итерации цикла. Однако это понятие не относится к parfor-контуры.
В parfor-loop, значение X не обновляется непосредственно внутри каждого потока. Скорее, добавления d(i) выполняются в каждом потоке, с i диапазон по подмножеству 1:n выполняется на этом потоке. Затем программное обеспечение накапливает результаты в X.
Аналогичным образом, сокращение:
r=r<op> x(i)
r=r<op>x(1)] <op>x(2)...<op>x(n)
<op> сначала применяется к x(1)...x(n), то частичный результат применяется к r.Если работа <op> принимает два ввода, он должен отвечать одному из следующих критериев:
Взять два аргумента typeof(x(i)) и возвращение typeof(x(i))
Взять один аргумент typeof(r) и один из typeof(x(i)) и возвращение typeof(r)
Используйте одну и ту же функцию сокращения или операцию во всех назначениях сокращения. Для переменной сокращения необходимо использовать одну и ту же функцию сокращения или операцию во всех назначениях сокращения для этой переменной. В следующем примере parfor-loop слева недопустим, так как назначение сокращения использует + в одном случае, и * в другом.
| Недопустимое использование переменной сокращения | Допустимое использование переменной сокращения |
|---|---|
parfor i = 1:n
if A > 5*k
A = A + 1;
else
A = A * 2;
end
|
parfor i = 1:n
if A > 5*k
A = A * 3;
else
A = A * 2;
end
|
Ограничения для параметров функции сокращения и типов возврата. Сокращение r=r<op> x(i), должны принимать аргументы typeof(x(i)) и возвращение typeof(x(i)) или взять аргументы typeof(r) и typeof(x(i)) и возвращение typeof(r).
В следующем примере в недопустимом цикле r является типом с фиксированной точкой и 2 нет. Чтобы устранить эту проблему, приведите 2 быть того же типа, что и r.
| Недопустимое использование переменной сокращения | Допустимое использование переменной сокращения |
|---|---|
function r = fiops(in)
r=fi(in,'WordLength',20,...
'FractionLength',14,...
'SumMode','SpecifyPrecision',...
'SumWordLength',20,...
'SumFractionLength',14,...
'ProductMode', 'SpecifyPrecision',...
'ProductWordLength',20,...
'ProductFractionLength',14);
parfor i = 1:10
r = r*2;
end |
r=fi(in,'WordLength',20,...
'FractionLength',14,...
'SumMode','SpecifyPrecision',...
'SumWordLength',20,...
'SumFractionLength',14,...
'ProductMode','SpecifyPrecision',...
'ProductWordLength',20,...
'ProductFractionLength',14);
T = r.numerictype;
F = r.fimath;
parfor i = 1:10
r = r*fi(2,T,F);
end |
В следующем примере функция сокращения fcn недопустим, поскольку он не обрабатывает регистр при вводе u является фиксированной точкой. ( + и * операции автоматически полиморфны.) Необходимо написать полиморфную версию fcn для обработки ожидаемых типов ввода.
| Недопустимое использование переменной сокращения | Допустимое использование переменной сокращения |
|---|---|
function [y0, y1, y2] = pfuserfcn(u)
y0 = 0;
y1 = 1;
[F, N] = fiprops();
y2 = fi(1,N,F);
parfor (i=1:numel(u),12)
y0 = y0 + u(i);
y1 = y1 * u(i);
y2 = fcn(y2, u(i));
end
end
function y = fcn(u, v)
y = u * v;
end |
function [y0, y1, y2] = pfuserfcn(u)
y0 = 0;
y1 = 1;
[F, N] = fiprops();
y2 = fi(1,N,F);
parfor (i=1:numel(u),12)
y0 = y0 + u(i);
y1 = y1 * u(i);
y2 = fcn(y2, u(i));
end
end
% fcn handles inputs of type double
% and fi
function y = fcn(u, v)
if isa(u,'double')
y = u * v;
else
[F, N] = fiprops();
y = u * fi(v,N,F);
end
end
function [F, N] = fiprops()
N = numerictype(1,96,30);
F = fimath('ProductMode',...
'SpecifyPrecision',...
'ProductWordLength',96);
end
|
Назначения сокращения. Кодер MATLAB не позволяет считывать переменные сокращения в любом месте parfor-loop, за исключением операторов сокращения. В следующем примере вызов foo(r) после выписки о сокращении r=r+i приводит к недопустимости цикла.
function r = temp %#codegen
r = 0;
parfor i=1:10
r = r + i;
foo(r);
end
end
Ассоциативность в назначениях сокращения. При использовании пользовательской функции f в определении переменной редукции, чтобы получить детерминированное поведение parfor-циклы, функция редукции f должен быть ассоциативным.
Примечание
Если f не является ассоциативным, кодер MATLAB не генерирует ошибку. Необходимо написать код, соответствующий этой рекомендации.
Чтобы быть ассоциативной, функция f должны удовлетворять следующим требованиям для всех a, b, и c:
f(a,f(b,c)) = f(f(a,b),c)
Коммутативность в назначениях сокращения. Некоторые ассоциативные функции, в том числе +, ., min, и max, также являются коммутативными. То есть удовлетворяют следующим для всех a и b:
f(a,b) = f(b,a)
Функция f назначения сокращения должны быть коммутативными. Если f не является коммутативным, различные выполнения цикла могут привести к различным ответам.
Если f является известным некоммутативным встроенным, программное обеспечение предполагает, что он является коммутативным.
Временная переменная является переменной, которая является целью прямого неиндексированного назначения, но не является переменной сокращения. В следующем parfor-луп, a и d временные переменные:
a = 0;
z = 0;
r = rand(1,10);
parfor i = 1:10
a = i; % Variable a is temporary
z = z + i;
if i <= 5
d = 2*a; % Variable d is temporary
end
end
В отличие от поведения for- цикл, перед каждой итерацией parfor-loop, кодер MATLAB эффективно очищает временные переменные. Поскольку итерации должны быть независимыми, значения временных переменных не могут передаваться из одной итерации цикла в другую. Поэтому временные переменные должны быть установлены внутри тела parfor-контур, чтобы их значения определялись отдельно для каждой итерации.
Временная переменная в контексте parfor оператор отличается от переменной с таким же именем, которая существует вне цикла.
Поскольку временные переменные очищаются в начале каждой итерации, кодер MATLAB может обнаружить определенные случаи, в которых итерация в цикле использует временную переменную до того, как она будет задана в этой итерации. В этом случае кодер MATLAB выдает статическую ошибку, а не ошибку времени выполнения, поскольку есть мало смысла разрешать выполнение в случае возникновения ошибки времени выполнения. Например, предположим, что вы пишете:
b = true;
parfor i = 1:n
if b && some_condition(i)
do_something(i);
b = false;
end
...
end
Этот контур допустим как обычный for-loop, но как parfor-луп, b является временной переменной, поскольку она происходит непосредственно в качестве цели назначения внутри цикла. Поэтому он очищается в начале каждой итерации, поэтому его использование в условии if не инициализирован. (При изменении parfor кому for, значение b предполагает последовательное выполнение цикла, так что do_something(i) выполняется только для нижних значений i до b установлено false.)