parfor
и for
- циклы и другие требования parfor
parfor
- циклыВы не можете использовать parfor
- цикл в другом parfor
- цикл. Как пример, не позволено следующее вложение parfor
- циклы:
parfor i = 1:10 parfor j = 1:5 ... end end
Вы не можете вложить parfor
непосредственно в другом parfor
- цикл. parfor
- цикл может вызвать функцию, которая содержит parfor
- цикл, но вы не получаете дополнительного параллелизма.
Анализатор кода в Редакторе MATLAB® отмечает использование parfor
в другом parfor
- цикл:
Вы не можете вложить parfor
- циклы, потому что распараллеливание может быть выполнено только на одном уровне. Поэтому выберите который цикл запуститься параллельно, и преобразовать другой цикл в for
- цикл.
Рассмотрите следующие проблемы производительности при контакте с вложенными циклами:
Параллельная обработка подвергается наверху. Обычно необходимо запустить внешний цикл параллельно, потому что наверху только происходит однажды. Если при запуске внутренний цикл параллельно, то каждое несколько выполнения parfor
подвергается издержкам. Смотрите Преобразовывают Вложенные циклы for в циклы parfor для примера, как измерить параллель наверху.
Убедитесь, что количество итераций превышает количество рабочих. В противном случае вы не используете всех доступных рабочих.
Попытайтесь сбалансировать parfor
- времена итерации цикла. parfor
пытается компенсировать некоторую неустойчивость загрузки.
Всегда запускайте наиболее удаленный цикл параллельно, потому что вы уменьшаете параллель наверху.
Можно также использовать функцию, которая использует parfor
, и встройте его в parfor
- цикл. Распараллеливание происходит только на внешнем уровне. В следующем примере вызовите функциональный MyFun.m
во внешнем parfor
- цикл. Внутренний parfor
- цикл, встроенный в MyFun.m
, запускается последовательно, не параллельно.
parfor i = 1:10 MyFun(i) end function MyFun(i) parfor j = 1:5 ... end end
Вложенный parfor
- циклы обычно не приносят вам вычислительной пользы.
for
- циклы к parfor
- циклыТипичное использование вложенных циклов должно продвинуться через массив с помощью одной переменной цикла, чтобы индексировать одну размерность и переменную вложенного цикла, чтобы индексировать другую размерность. Каноническая форма:
X = zeros(n,m); for a = 1:n for b = 1:m X(a,b) = fun(a,b) end end
Следующий код показывает простой пример. Используйте tic
и toc
, чтобы измерить вычислительное необходимое время.
A = 100; tic for i = 1:100 for j = 1:100 a(i,j) = max(abs(eig(rand(A)))); end end toc
Elapsed time is 49.376732 seconds.
Можно параллелизировать любой из вложенных циклов, но вы не можете запустить обоих параллельно. Причина состоит в том, что рабочие в параллельном пуле не могут запустить, или доступ далее параллельны пулам.
Если цикл, считаемый i
, преобразован в parfor
- цикл, то каждый рабочий в пуле выполняет вложенные циклы с помощью счетчика цикла j
. Сами циклы j
не могут запуститься как parfor
на каждом рабочем.
Поскольку параллельная обработка подвергается наверху, необходимо выбрать тщательно, хотите ли вы преобразовать или внутреннее или внешний for
- цикл к parfor
- цикл. Следующий пример показывает, как измерить параллель наверху.
Сначала преобразуйте только внешний for
- цикл к parfor
- цикл. Используйте tic
и toc
, чтобы измерить вычислительное необходимое время. Используйте ticBytes
и tocBytes
, чтобы измериться, сколько данных передается и от рабочих в параллельном пуле.
Запустите новый код и запустите его снова. Первый показ медленнее, чем последующие выполнения, потому что параллельный пул занимает время, чтобы запустить и сделать код доступным для рабочих.
A = 100; tic ticBytes(gcp); parfor i = 1:100 for j = 1:100 a(i,j) = max(abs(eig(rand(A)))); end end tocBytes(gcp) toc
BytesSentToWorkers BytesReceivedFromWorkers __________________ ________________________ 1 32984 24512 2 33784 25312 3 33784 25312 4 34584 26112 Total 1.3514e+05 1.0125e+05 Elapsed time is 14.130674 seconds.
Затем преобразуйте только внутренний цикл в parfor
- цикл. Измерьте необходимое время и данные, переданные как в предыдущем случае.
A = 100; tic ticBytes(gcp); for i = 1:100 parfor j = 1:100 a(i,j) = max(abs(eig(rand(A)))); end end tocBytes(gcp) toc
BytesSentToWorkers BytesReceivedFromWorkers __________________ ________________________ 1 1.3496e+06 5.487e+05 2 1.3496e+06 5.4858e+05 3 1.3677e+06 5.6034e+05 4 1.3476e+06 5.4717e+05 Total 5.4144e+06 2.2048e+06 Elapsed time is 48.631737 seconds.
Если вы преобразовываете внутренний цикл в parfor
- цикл, и время и переданный объем данных намного больше, чем в параллельном внешнем цикле. В этом случае прошедшее время является почти тем же самым как во вложенном for
- пример цикла. Ускорение меньше, чем выполнение внешнего цикла параллельно, потому что у вас есть больше передачи данных и таким образом больше параллели наверху. Поэтому, если вы выполняете внутренний цикл параллельно, вы не извлекаете вычислительной пользы по сравнению с выполнением последовательного for
- цикл.
Если вы хотите уменьшать параллель наверху и ускорить ваше вычисление, запустить внешний цикл параллельно.
Если вы преобразовываете внутренний цикл вместо этого, то каждая итерация внешнего цикла инициирует отдельный parfor
- цикл. Таким образом, преобразование внутреннего цикла создает 100 parfor
- циклы. Каждое несколько выполнения parfor
подвергается наверху. Если вы хотите уменьшать параллель наверху, необходимо запустить внешний цикл параллельно вместо этого, потому что наверху только происходит однажды.
Если вы хотите ускорить свой код, всегда запускать внешний цикл параллельно, потому что вы уменьшаете параллель наверху.
for
- циклы: требования и ограниченияЕсли вы хотите преобразовать вложенный for
- цикл к parfor
- цикл, необходимо гарантировать, что переменные цикла правильно классифицируются, смотрите Переменные Поиска и устранения неисправностей в циклах parfor. Если ваш код не придерживается инструкций и ограничений, маркированных как требуется, вы получаете ошибку. MATLAB фиксирует некоторые из этих ошибок в то время, когда он читает код и других, когда он выполняет код. Эти ошибки маркированы как требуется (статичными) или Необходимыми (динамический) соответственно.
Необходимые (помехи): необходимо задать область значений for - цикла, вложенного в parfor - цикл постоянными числами или широковещательно передавать переменные. |
В следующем примере слева не работает код, потому что вы задаете верхний предел for
- цикл вызовом функции. Код справа предоставляет обходное решение первым определением широковещательной передачи или постоянной переменной вне parfor
- цикл:
Недопустимый | Допустимый |
---|---|
A = zeros(100, 200); parfor i = 1:size(A, 1) for j = 1:size(A, 2) A(i, j) = i + j; end end | A = zeros(100, 200); n = size(A, 2); parfor i = 1:size(A,1) for j = 1:n A(i, j) = i + j; end end |
Необходимые (помехи): индексная переменная для вложенного for - цикл никогда не должна явным образом присваиваться кроме в его for - цикл. |
Это ограничение требуется, потому что, изменяя вложенный for
- переменная цикла в теле цикла не может гарантировать, что область, индексированная for
- переменная цикла, доступна в каждом рабочем.
Код слева не допустим, потому что он пытается изменить значение вложенного for
- переменная цикла j
в теле цикла. Код справа предоставляет обходное решение путем присвоения вложенного for
- переменная цикла к временной переменной t
, и затем обновления t
.
Недопустимый | Допустимый |
---|---|
A = zeros(10); parfor i = 1:10 for j = 1:10 A(i, j) = 1; j = j+1; end end |
A = zeros(10); parfor i = 1:10 for j = 1:10 A(i, j) = 1; t = j; t = t + 1; end end |
Необходимые (помехи): Вы не можете индексировать или преобразовать вложенную переменную цикла for в нижний индекс. |
Это ограничение требуется, потому что индексация переменной цикла не может гарантировать независимость итераций.
Пример слева недопустим, потому что он пытается индексировать вложенный for
- переменная цикла j
. Пример справа удаляет эту индексацию.
Недопустимый | Допустимый |
---|---|
A = zeros(10); parfor i = 1:10 for j = 1:10 j(1); end end |
A = zeros(10); parfor i = 1:10 for j = 1:10 j; end end |
Необходимые (помехи): При использовании вложенного for - переменная цикла для индексации нарезанного массива, необходимо использовать переменную в простой форме, не как часть выражения. |
Например, следующий код слева не работает, но код справа делает:
Недопустимый | Допустимый |
---|---|
A = zeros(4, 11); parfor i = 1:4 for j = 1:10 A(i, j + 1) = i + j; end end | A = zeros(4, 11); parfor i = 1:4 for j = 2:11 A(i, j) = i + j - 1; end end |
Необходимые (помехи): Если вы используете вложенный for - цикл, чтобы индексировать в нарезанный массив, вы не можете использовать тот массив в другом месте в parfor - цикл. |
В следующем примере слева не работает код, потому что A
нарезан и индексирован во вложенном for
- цикл. Код справа работает, потому что v
присвоен A
за пределами вложенного цикла:
Недопустимый | Допустимый |
---|---|
A = zeros(4, 10); parfor i = 1:4 for j = 1:10 A(i, j) = i + j; end disp(A(i, j)) end | A = zeros(4, 10); parfor i = 1:4 v = zeros(1, 10); for j = 1:10 v(j) = i + j; end disp(v(j)) A(i, :) = v; end |
Необходимые (помехи): нарезанная выходная переменная может использоваться только в одном вложенном цикле for. |
Предположим, что вы используете несколько for
- циклы (не вложенный друг в друге) в parfor
- цикл, чтобы индексировать в один нарезанный массив. В этом случае for
- циклы должны циклично выполниться в той же области значений значений. В следующем примере код слева не работает потому что j
и цикл k
по различным значениям. Код справа работает, чтобы индексировать различные фрагменты нарезанного массива A
:
Недопустимый | Допустимый |
---|---|
A = zeros(4, 10); parfor i = 1:4 for j = 1:5 A(i, j) = i + j; end for k = 6:10 A(i, k) = pi; end end | A = zeros(4, 10); parfor i = 1:4 for j = 1:10 if j < 6 A(i, j) = i + j; else A(i, j) = pi; end end end |
parfor-
ограничения циклаТело parfor
- цикл не может сослаться на вложенную функцию. Однако это может вызвать вложенную функцию указателем на функцию. Попробуйте следующий пример. Обратите внимание на то, что A(idx) = nfcn(idx)
в parfor
- цикл не работает. Необходимо использовать feval
, чтобы вызвать указатель fcn
в parfor
- тело цикла.
function A = pfeg function out = nfcn(in) out = 1 + in; end fcn = @nfcn; parfor idx = 1:10 A(idx) = feval(fcn, idx); end end
>> pfeg Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers. ans = 2 3 4 5 6 7 8 9 10 11
Если вы используете указатели на функцию, которые относятся к вложенным функциям в parfor
- цикл, то значения внешне ограниченных по объему переменных не синхронизируются среди рабочих.
parfor
- циклыТело parfor
- цикл не может содержать parfor
- цикл. Для получения дополнительной информации смотрите Вложенные циклы parfor.
spmd
Тело parfor
- цикл не может содержать оператор spmd
, и оператор spmd
не может содержать parfor
- цикл. Причина состоит в том, что рабочие не могут запустить, или доступ далее параллельны пулам.
break
и операторы return
Тело parfor
- цикл не может содержать операторы break
или return
. Рассмотрите parfeval
или parfevalOnAll
вместо этого, потому что можно использовать cancel
на них.
Тело parfor
- цикл не может содержать объявления переменной persistent
или global
. Причина состоит в том, что эти переменные не синхронизируются между рабочими. Можно использовать переменные global
или persistent
в функциях, но их значение видимо только рабочему, который создает их. Вместо переменных global
это - лучшая практика, чтобы использовать аргументы функции для стоимости акций.
Чтобы узнать больше о переменных требованиях, смотрите Переменные Поиска и устранения неисправностей в циклах parfor.
Если скрипт вводит переменную, вы не можете вызвать этот скрипт из parfor
- оператор spmd
или цикл. Причина состоит в том, что этот скрипт вызвал бы нарушение прозрачности. Для получения дополнительной информации смотрите, Гарантируют Прозрачность в циклах parfor или spmd Операторах.
Можно задать анонимную функцию в теле parfor
- цикл. Однако нарезанные выходные переменные в анонимных функциях не поддержаны. Можно работать вокруг этого при помощи временной переменной для нарезанной переменной, как показано в следующем примере.
x = 1:10; parfor i=1:10 temp = x(i); anonymousFunction = @() 2*temp; x(i) = anonymousFunction() + i; end disp(x);
Для получения дополнительной информации о нарезанных переменных смотрите Нарезанные Переменные.
inputname
Используя inputname
, чтобы возвратить имя переменной рабочей области, соответствующее номеру аргумента, не поддержан в parfor
- циклы. Причина состоит в том, что у рабочих parfor
нет доступа к рабочей области рабочего стола MATLAB. Чтобы работать вокруг этого, вызовите inputname
перед parfor
, как показано в следующем примере.
a = 'a'; myFunction(a) function X = myFunction(a) name = inputname(1); X = []; parfor i=1:2 X = strcat(X,name); end end
load
Синтаксисы load
, которые не присваивают выходной структуре, не поддержаны в parfor
- циклы. В parfor
всегда присваивайте вывод load
к структуре.
nargin
или функции nargout
Следующее использование не поддержано в parfor
- циклы:
Используя nargin
или nargout
без аргумента функции
Используя narginchk
или nargoutchk
, чтобы проверить количество аргументов ввода или вывода в вызове функции, которая является выполняющимся в данным моментом
Причина состоит в том, что у рабочих нет доступа к рабочей области рабочего стола MATLAB. Чтобы работать вокруг этого, вызовите эти функции перед parfor
, как показано в следующем примере.
myFunction('a','b') function X = myFunction(a,b) nin = nargin; parfor i=1:2 X(i) = i*nin; end end
Можно вызвать файлы скрипта Псевдокода из parfor
- цикл, но скрипты Псевдокода не могут содержать parfor
- цикл. Чтобы работать вокруг этого, используйте функцию Псевдокода вместо скрипта Псевдокода.
parfeval
| parfevalOnAll
| parfor