exponenta event banner

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

Вложенный parfor- Петли

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

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

Совет

Нельзя гнездиться parfor непосредственно в другой parfor-луп. A parfor-loop может вызывать функцию, содержащую parfor-loop, но дополнительного параллелизма не получается.

Анализатор кода в редакторе MATLAB ® помечает использование parfor внутри другого parfor-loop:

Нельзя гнездиться parfor-циклы, поскольку параллелизация может выполняться только на одном уровне. Поэтому выберите параллельный цикл и преобразуйте другой цикл в for-луп.

При работе с вложенными циклами необходимо учитывать следующие проблемы с производительностью:

  • Параллельная обработка требует накладных расходов. Как правило, внешний цикл следует запускать параллельно, поскольку служебные данные возникают только один раз. Если внутренний цикл выполняется параллельно, то каждый из нескольких parfor казни влекут за собой накладные расходы. Пример измерения параллельных накладных расходов см. в разделе Преобразование вложенных для-петель в пакетные-петли.

  • Убедитесь, что число итераций превышает число работников. В противном случае используются не все доступные работники.

  • Постарайтесь сбалансировать parfor- время итерации цикла. parfor пытается компенсировать некоторый дисбаланс нагрузки.

Совет

Всегда запускайте внешний цикл параллельно, так как вы сокращаете параллельные издержки.

Также можно использовать функцию, использующую parfor и встроить его в parfor-луп. Параллелизация происходит только на внешнем уровне. В следующем примере вызовите функцию MyFun.m внутри внешней parfor-луп. Внутреннее parfor-loop встроен в 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-loop, затем каждый работник в пуле выполняет вложенные циклы с помощью 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Пример -loop. Ускорение меньше, чем параллельное выполнение внешнего цикла, потому что у вас больше передачи данных и, следовательно, больше параллельных служебных данных. Поэтому при параллельном выполнении внутреннего цикла вычислительные преимущества по сравнению с последовательным for-луп.

Если вы хотите уменьшить параллельные издержки и ускорить вычисления, запустите внешний цикл параллельно.

Если вместо этого преобразовать внутренний цикл, то каждая итерация внешнего цикла инициирует отдельный parfor-луп. То есть преобразование внутреннего цикла создает 100 parfor-контуры. Каждый из нескольких parfor казни влекут за собой накладные расходы. Если требуется уменьшить накладные расходы параллельно, следует запустить внешний цикл параллельно, поскольку накладные расходы возникают только один раз.

Совет

Если вы хотите ускорить код, всегда запускайте внешний цикл параллельно, потому что вы сокращаете параллельные издержки.

Вложенный for-Контуры: требования и ограничения

Если требуется преобразовать вложенный элемент for-закольцовывание в parfor-loop, необходимо убедиться, что переменные цикла правильно классифицированы, см. раздел Устранение неполадок с переменными в parfor-Loops. Если ваш код не соответствует инструкциям и ограничениям, помеченным как обязательный, вы получите ошибку. MATLAB обнаруживает некоторые из этих ошибок во время чтения кода. Эти ошибки помечены как обязательные (статические).

Обязательный (статический): необходимо определить диапазон for-loop вложен в parfor-закольцовывание по постоянным числам или переменным вещания.

В следующем примере код слева не работает, поскольку вы определяете верхний предел for-закольцовывание вызовом функции. Код справа обеспечивает обходной путь путем определения широковещательной или постоянной переменной за пределами parfor-loop:

ИнвалидДействительный
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-loop не должен назначаться явно, кроме как его for заявление.

Необходимо следовать этому ограничению. Если вложенный forпеременная -loop изменяется в любом месте parfor-контур, отличный от его for оператор, регион, индексированный forПеременная -loop не гарантированно доступна для каждого работника.

Код слева недопустим, поскольку пытается изменить значение вложенного forпеременная -loop j в теле петли. Код справа обеспечивает обходной путь путем назначения вложенного forпеременная -loop во временную переменную 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переменная -loop.

Необходимо следовать этому ограничению. Если вложенный forПеременная -loop индексирована, итерации не гарантированы как независимые.

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

Например, следующий код слева не работает, а код справа:

ИнвалидДействительный
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-loop для индексирования в разрезованный массив, этот массив нельзя использовать в другом месте в 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- Ограничения цикла

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

Тело parfor-loop не может ссылаться на вложенную функцию. Однако он может вызывать вложенную функцию с помощью дескриптора функции. Попробуйте выполнить следующий пример. Обратите внимание, что A(idx) = nfcn(idx) в parfor-loop не работает. Необходимо использовать 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-loop не может содержать parfor-луп. Дополнительные сведения см. в разделе Вложенные пакетные контуры.

Вложенный spmd Заявления

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

break и return Заявления

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

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

Тело parfor-loop не может содержать global или persistent объявления переменных. Причина в том, что эти переменные не синхронизированы между работниками. Вы можете использовать global или persistent переменные внутри функций, но их значение видно только для создающего их работника. Вместо global переменные, лучше использовать аргументы функции для совместного использования значений.

Дополнительные сведения о требованиях к переменным см. в разделе Устранение неполадок переменных в контурах parfor.

Сценарии

Если сценарий вводит переменную, этот сценарий нельзя вызвать из parfor-луп или spmd заявление. Причина в том, что этот сценарий может привести к нарушению прозрачности. Дополнительные сведения см. в разделе Обеспечение прозрачности в пакетах-петлях или инструкциях 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 которые не назначаются структуре вывода, не поддерживаются внутри 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

Сценарии P-кода

Можно вызывать файлы сценариев P-кода из parfor-loop, но сценарии P-кода не могут содержать parfor-луп. Чтобы обойти это, используйте функцию P-кода вместо сценария P-кода.

См. также

| |

Связанные темы