parfor
- циклыMATLAB® Coder™ классифицирует переменные в parfor
- цикл в одну из категорий в следующей таблице. Это не поддерживает переменные, которые это не может классифицировать. Если 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
является фиксированной точкой. (Операции +
и *
являются автоматически полиморфными.) Необходимо записать полиморфную версию 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
В отличие от поведения 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
.)