parfor
и for
-Циклы и другие parfor
Требованияparfor
- ЦиклыВы не можете использовать parfor
-цикл внутри другого parfor
-цикл. В качестве примера можно привести следующее вложение parfor
-циклы не разрешены:
parfor i = 1:10 parfor j = 1:5 ... end end
Совет
Вы не можете гнездиться parfor
непосредственно внутри другого parfor
-цикл. A parfor
-цикл может вызвать функцию, которая содержит parfor
-цикл, но вы не получаете никакого дополнительного параллелизма.
Анализатор кода в MATLAB® Редактор помечает использование parfor
внутри другого parfor
-цикл:
Вы не можете гнездиться parfor
-циклы, потому что параллелизация может быть выполнена только на одном уровне. Поэтому выберите цикл, который будет запускаться параллельно, и преобразуйте другой цикл в for
-цикл.
Примите во внимание следующие проблемы эффективности при работе с вложенными циклами:
Параллельная обработка сопряжена с накладными расходами. Обычно следует запускать внешний контур параллельно, потому что накладные расходы возникают только один раз. Если вы запускаете внутренний цикл параллельно, то каждый из нескольких parfor
выполнение влечет за собой накладные расходы. Пример измерения параллельных накладных расходов см. в разделе Преобразование вложенных циклов для циклов в циклы 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
-loop, затем каждый рабочий процесс в пуле выполняет вложенные циклы с помощью j
счетчик цикла. The 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
-loop, и время, и количество переданных данных намного больше, чем в параллельном внешнем контуре. В этом случае прошедшее время почти совпадает с временем во вложенном for
Цикл. Скорость меньше, чем параллельный запуск внешнего контура, потому что у вас больше передачи данных и, следовательно, больше параллельных накладных расходов. Поэтому, если вы выполняете внутренний цикл параллельно, вы не получаете вычислительных преимуществ по сравнению с запуском последовательного for
-цикл.
Если вы хотите уменьшить параллельные накладные расходы и ускорить расчеты, запустите внешний контур параллельно.
Если вы преобразовываете вместо этого внутренний цикл, то каждая итерация внешнего контура инициирует отдельное parfor
-цикл. То есть преобразование внутреннего цикла создает 100 parfor
-циклы. Каждый из нескольких parfor
выполнение влечет за собой накладные расходы. Если вы хотите уменьшить параллельные накладные расходы, следует запустить внешний контур параллельно, потому что накладные расходы возникают только один раз.
Совет
Если вы хотите ускорить код, всегда запускайте внешний контур параллельно, потому что вы уменьшаете параллельные накладные расходы.
for
-Циклы: Требования и ограниченияЕсли вы хотите преобразовать вложенное for
-цикл на parfor
-loop, необходимо убедиться, что переменные цикла правильно классифицированы, см. «Поиск и устранение проблем с переменными в циклах 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
Цикл изменяется в любом месте parfor
-цикл кроме его for
оператор, область, индексированная for
- переменная loop не гарантирована для каждого работника.
Код слева недопустим, поскольку он пытается изменить значение вложенного 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
оператор не может содержать 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
Вы можете вызвать файлы скрипта P-кода из parfor
-цикл, но скрипты P-кода не могут содержать parfor
-цикл. Чтобы обойти это, используйте функцию P-кода вместо скрипта P-кода.
parfeval
| parfevalOnAll
| parfor