Вложенный parfor и for- Циклы и другой parfor Требования

Вложенный parfor- Циклы

Вы не можете использовать parfor- цикл в другом parfor- цикл. Как пример, следующее вложение parfor- циклы не позволены:

parfor i = 1:10
    parfor j = 1:5
        ...
    end
end

Совет

Вы не можете вложить parfor непосредственно в другом parfor- цикл. A parfor- цикл может вызвать функцию, которая содержит a 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 фиксирует некоторые из этих ошибок в то время, когда он читает код. Эти ошибки помечены как требуется (статическими).

Необходимые (помехи): необходимо задать область значений a 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- переменная цикла изменяется где угодно в parfor- цикл кроме его 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- переменная цикла индексируется, итерации, как гарантируют, не будут независимы.

Пример слева недопустим, потому что он пытается индексировать вложенный 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

parfor- Ограничения цикла

Вложенные функции

Тело a 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 Операторы

Тело a parfor- цикл не может содержать spmd оператор, и spmd оператор не может содержать a parfor- цикл. Причина состоит в том, что рабочие не могут запустить, или доступ далее параллельны пулам.

break и return Операторы

Тело parfor- цикл не может содержать break или return операторы. Рассмотреть parfeval или parfevalOnAll вместо этого, потому что можно использовать cancel на них.

Глобальные и персистентные переменные

Тело parfor- цикл не может содержать global или persistent объявления переменной. Причина состоит в том, что эти переменные не синхронизируются между рабочими. Можно использовать 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);
    
    parfor i=1:2
        X(i).(name) = i;
    end
end

load Функции

Синтаксисы load это не присваивает структуре output, не поддержаны в 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- цикл. Чтобы работать вокруг этого, используйте функцию Псевдокода вместо скрипта Псевдокода.

Смотрите также

| |

Похожие темы