parfor
- ЦиклыMATLAB® Coder™ классифицирует переменные внутри parfor
-включиться в одну из категорий в следующей таблице. Он не поддерживает переменные, которые не может классифицировать. Если a parfor
-цикл содержит переменные, которые не могут быть однозначно классифицированы или если переменная нарушает ограничения своей категории, parfor
-цикл генерирует ошибку.
Классификация | Описание |
---|---|
Цикл | Служит индексом цикла для массивов |
Нарезанный | Массив, сегменты которого управляются различными итерациями цикла |
Передача | Переменная, заданная перед циклом, значение которой используется внутри цикла, но не назначена внутри цикла |
Сокращение | Накапливает значение через итерации цикла, независимо от порядка итерации |
Временный | Переменная, созданная внутри цикла, но в отличие от разрезанных или сокращенных переменных, недоступная за пределами цикла |
Каждая из этих классификаций переменных появляется в этом фрагменте кода:
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
-цикл, который использует скалярное назначение сокращения. Он использует переменную сокращения 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
-цикл, переменная X
в каждой итерации это значение будет получено либо перед входом в цикл, либо после предыдущей итерации цикла. Однако эта концепция не относится к parfor
-циклы.
В parfor
-цикл, значение 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
-цикл слева недопустим, поскольку используется назначение сокращения +
в одном образце и *
в другом.
Недопустимое использование переменной сокращения | Допустимое использование переменной сокращения |
---|---|
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
является фиксированной точкой. (The +
и *
операции являются автоматически полиморфными.) Необходимо написать полиморфную версию 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 Coder не позволяет считывать переменные сокращения нигде в parfor
-цикл, кроме как в операторах сокращения. В следующем примере вызов 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 Coder не генерирует ошибку. Необходимо написать код, соответствующий этой рекомендации.
Чтобы быть ассоциативной, функция 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
В отличие от поведения a for
-цикл, перед каждой итерацией parfor
-цикл, MATLAB Coder эффективно очищает временные переменные. Поскольку итерации должны быть независимыми, значения временных переменных не могут быть переданы от одной итерации цикла к другой. Поэтому временные переменные должны быть установлены внутри тела parfor
-цикл, так что их значения задаются отдельно для каждой итерации.
Временная переменная в контексте parfor
оператор отличается от переменной с таким же именем, которое существует вне цикла.
Поскольку временные переменные очищаются в начале каждой итерации, MATLAB Coder может обнаружить определенные случаи, в которых итерация через цикл использует временную переменную, прежде чем она будет установлена в этой итерации. В этом случае MATLAB Coder выдает статическую ошибку, а не ошибку времени выполнения, поскольку мало точки разрешать выполнение в случае возникновения ошибки времени выполнения. Например, предположим, вы пишете:
b = true; parfor i = 1:n if b && some_condition(i) do_something(i); b = false; end ... end
Этот цикл приемлем как обычный for
-цикл, но как parfor
-цикл, b
является временной переменной, поскольку она происходит непосредственно как цель назначения внутри цикла. Поэтому он очищается в начале каждой итерации, поэтому его использование в состоянии if
не инициализирован. (Если вы меняете parfor
на for
, значение b
принимает последовательное выполнение цикла, так что do_something(i)
выполняется только для нижних значений i
до b
задан false
.)