parfor
Можно улучшать производительность parfor
- циклы в различных способах. Это включает параллельное создание массивов в цикле; профилирование parfor
- циклы; разрезание массивов; и оптимизация вашего кода по локальным рабочим перед работой кластера.
Когда вы создаете большой массив в клиенте перед вашим parfor
- цикл и получаете доступ к нему в цикле, вы можете наблюдать медленное подписание своего кода. Чтобы улучшать производительность, скажите каждому рабочему MATLAB® создавать его собственные массивы или фрагменты их, параллельно. Можно сэкономить время передачи данных от клиента рабочим, прося, чтобы каждый рабочий создал его собственную копию этих массивов, параллельно, в цикле. Рассмотрите изменение вашей обычной практики инициализации переменных перед for
- цикл, избежав бесполезного повторения в цикле. Вы можете найти, что параллельное создание массивов в цикле улучшает производительность.
Повышение производительности зависит от различных факторов, включая
размер массивов
время должно было создать массивы
доступ рабочего ко всем или части массивов
количество итераций цикла, которые выполняет каждый рабочий
Полагайте, что все включает этот список, когда вы рассматриваете, чтобы преобразовать for
- циклы к parfor
- циклы. Для получения дополнительной информации смотрите, Преобразовывают циклы for В циклы parfor.
Как альтернатива, полагайте, что функция 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
>> 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, смотрите Профиль, чтобы Улучшать Производительность (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
Запустите код и отметьте прошедшее время.
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
- цикл, то используемый в parfor
- цикл, это должно быть передано каждому работнику 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
- цикл относительно времени выполнения. Это может зависеть от многих факторов, включая то, сколько процессоров и удаляет сердцевину вашей машины, имеет. Ключевой пункт здесь - то, что кластерная сила имеет больше ядер в наличии, чем ваша локальная машина. Если ваш код может быть многопоточным 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 |
Работая на удаленном кластере, вы можете найти различное поведение, когда рабочие могут одновременно создать свои массивы, сохранив время трансфера. Поэтому код, который оптимизирован для локальных рабочих, не может быть оптимизирован для кластерных рабочих, и наоборот.