parfor РаботаВы можете повысить производительность parfor- петли различными способами. Это включает параллельное создание массивов внутри цикла; профилирование parfor-контуры; массивы нарезки; и оптимизация кода для локальных работников перед запуском в кластере.
При создании большого массива в клиенте перед parfor-loop, и доступ к нему в цикле, вы можете наблюдать медленное выполнение кода. Чтобы повысить производительность, попросите каждого работника MATLAB ® параллельно создавать собственные массивы или их части. Можно сохранить время передачи данных от клиента к работникам, попросив каждого работника создать свою собственную копию этих массивов параллельно внутри цикла. Рассмотрите возможность изменения обычной практики инициализации переменных перед for-луп, избегая ненужного повторения внутри цикла. Можно обнаружить, что параллельное создание массивов внутри цикла повышает производительность.
Повышение производительности зависит от различных факторов, в том числе
размер массивов
время, необходимое для создания массивов
рабочий доступ ко всем массивам или к их части
количество итераций цикла, которые выполняет каждый работник
Учитывать все факторы в этом списке, когда вы собираетесь конвертировать for-закольцовывает в parfor-контуры. Дополнительные сведения см. в разделе Преобразование циклов for-Loops в контуры parfor-Loops.
В качестве альтернативы рассмотрим parallel.pool.Constant для установки переменных на работников пула перед циклом. Эти переменные остаются на рабочих после завершения цикла и остаются доступными для нескольких parfor-контуры. Вы можете повысить производительность с помощью parallel.pool.Constant, поскольку данные передаются работникам только один раз.
В этом примере сначала создается набор больших данных D и выполнить parfor-закольцовывание доступа D. Тогда вы используете D для построения parallel.pool.Constant объект, позволяющий повторно использовать данные путем копирования D каждому работнику. Измерить прошедшее время с помощью tic и toc для каждого случая и обратите внимание на разницу.
function constantDemo D = rand(1e7, 1); tic for i = 1:20 a = 0; parfor j = 1:60 a = a + sum(D); end end toc tic D = parallel.pool.Constant(D); for i = 1:20 b = 0; parfor j = 1:60 b = b + sum(D.Value); end end toc end
>> constantDemo Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers. Elapsed time is 63.839702 seconds. Elapsed time is 10.194815 seconds.
parfor-закольцовывание с помощью parallel.pool.Constant объект.parfor- петлиМожно профилировать parfor-закольцовывание путем измерения времени, прошедшего с помощью tic и toc. Можно также измерить количество данных, переносимых к работникам и от них в параллельном пуле с помощью ticBytes и tocBytes. Обратите внимание, что это отличается от профилирования кода MATLAB в обычном смысле с помощью профилировщика MATLAB, см. раздел Профилирование кода для повышения производительности.
В этом примере вычисляется спектральный радиус матрицы и преобразуется for-закольцовывание в parfor-луп. Измерьте результирующее ускорение и объем передаваемых данных.
В редакторе MATLAB введите следующее: for-луп. Добавить tic и toc для измерения прошедшего времени. Сохранить файл как MyForLoop.m.
function a = MyForLoop(A) tic for i = 1:200 a(i) = max(abs(eig(rand(A)))); end toc end
Запустите код и запишите истекшее время.
a = MyForLoop(500);
Elapsed time is 31.935373 seconds.
В MyForLoop.m, замените for-закольцовывание с помощью parfor-луп. Добавить ticBytes и tocBytes для измерения объема данных, переносимых к работникам и от них в параллельном пуле. Сохранить файл как MyParforLoop.m.
ticBytes(gcp); parfor i = 1:200 a(i) = max(abs(eig(rand(A)))); end tocBytes(gcp)
Запустите новый код и запустите его еще раз. Следует отметить, что первый прогон выполняется медленнее, чем второй прогон, поскольку необходимо запустить параллельный пул и сделать код доступным для работников. Обратите внимание на прошедшее время для второго прогона.
По умолчанию MATLAB автоматически открывает параллельный пул работников на локальном компьютере.
a = MyParforLoop(500);
Starting parallel pool (parpool) using the 'local' profile ... connected to 4 workers.
...
BytesSentToWorkers BytesReceivedFromWorkers
__________________ ________________________
1 15340 7024
2 13328 5712
3 13328 5704
4 13328 5728
Total 55324 24168
Elapsed time is 10.760068 seconds. parfor-луп.Если переменная инициализирована перед parfor-loop, затем используется внутри parfor-loop, он должен быть передан каждому работнику MATLAB, оценивающему итерации цикла. Из клиентской рабочей области передаются только переменные, используемые в цикле. Однако если все вхождения переменной индексируются переменной цикла, каждый работник получает только нужную ему часть массива.
В качестве примера сначала выполняется parfor-закольцовывание с использованием разделенной переменной и измерение прошедшего времени.
% Sliced version M = 100; N = 1e6; data = rand(M, N); tic parfor idx = 1:M out2(idx) = sum(data(idx, :)) ./ N; end toc
Elapsed time is 2.261504 seconds.
Теперь предположим, что вы случайно используете ссылку на переменную data вместо N внутри parfor-луп. Проблема здесь в том, что вызов size(data, 2) преобразует разделенную переменную в широковещательную (несрезанную) переменную.
% Accidentally non-sliced version clear M = 100; N = 1e6; data = rand(M, N); tic parfor idx = 1:M out2(idx) = sum(data(idx, :)) ./ size(data, 2); end toc
Elapsed time is 8.369071 seconds.
В этом случае можно легко избежать использования без среза data, поскольку результат является константой и может быть вычислен вне цикла. Как правило, можно выполнять вычисления, зависящие только от широковещательных данных перед началом цикла, поскольку широковещательные данные не могут быть изменены внутри цикла. В этом случае вычисление является тривиальным и приводит к скалярному результату, что позволяет извлечь вычисления из цикла.
Выполнение кода на локальных рабочих может обеспечить удобство тестирования приложения без использования ресурсов кластера. Однако при использовании местных работников имеются определенные недостатки или ограничения. Поскольку передача данных не происходит по сети, поведение передачи на локальных рабочих может не указывать на то, как она обычно будет происходить по сети.
При работе с локальными работниками, поскольку все рабочие сеансы MATLAB выполняются на одной и той же машине, повышение производительности от parfor-loop относительно времени выполнения. Это может зависеть от многих факторов, включая количество процессоров и ядер. Ключевой момент заключается в том, что кластер может иметь больше ядер, чем локальный компьютер. Если код может быть многопоточным с помощью MATLAB, то единственный способ быстрее - использовать больше ядер для работы над проблемой, используя кластер.
Можно поэкспериментировать, чтобы проверить, быстрее ли создавать массивы перед циклом (как показано слева ниже), а не чтобы каждый работник создавал собственные массивы внутри цикла (как показано справа).
Попробуйте выполнить следующие примеры локального запуска параллельного пула и обратите внимание на разницу во времени выполнения для каждого цикла. Сначала откройте локальный параллельный пул:
parpool('local')Выполните следующие примеры и повторите выполнение. Следует отметить, что первый прогон для каждого случая выполняется медленнее, чем второй прогон, поскольку необходимо запустить параллельный пул и сделать код доступным для работников. Обратите внимание на прошедшее время, для каждого случая, для второго прогона.
tic; n = 200; M = magic(n); R = rand(n); parfor i = 1:n A(i) = sum(M(i,:).*R(n+1-i,:)); end toc |
tic; n = 200; parfor i = 1:n M = magic(n); R = rand(n); A(i) = sum(M(i,:).*R(n+1-i,:)); end toc |
Работая в удаленном кластере, вы можете найти другое поведение, так как работники могут одновременно создавать свои массивы, экономя время передачи. Поэтому код, оптимизированный для локальных работников, может быть не оптимизирован для работников кластера, и наоборот.