spmd
, parfor
, и parfeval
Чтобы запустить расчеты параллельно, можно использовать parfor
, parfeval
, parfevalOnAll
, или spmd
. Каждая конструкция опирается на различные концепции параллельного программирования. Если вам требуется, чтобы работники общались во время расчетов, используйте parfeval
, parfevalOnAll
, или spmd
.
Использовать parfeval
или parfevalOnAll
если ваш код можно разделить на набор задач, где каждая задача может зависеть от выхода других задач.
Использование spmd
если вам требуется коммуникация между работниками во время расчета.
Расчеты с parfeval
лучше всего представлены как график, подобный доске Канбана с блокировкой. Как правило, результаты собираются с работников после завершения расчетов. Можно собрать результаты от выполнения parfeval
операция при помощи afterEach
или afterAll
. Обычно результаты используются в дальнейших вычислениях.
Расчеты с spmd
лучше всего представлены блок-схемой, подобной рабочему процессу водопада. Рабочий процесс пула, выполняющий spmd
операторы называются лабораторией. Результаты могут быть собраны из лабораторий во время расчетов. Иногда лаборатории должны общаться с другими лабораториями, прежде чем они смогут закончить расчет.
Если вы не уверены, спросите себя следующее: в рамках моего коммуникационного параллельного кода можно ли выполнить каждый расчет без какого-либо общения между работниками? Если да, используйте parfeval
. В противном случае используйте spmd
.
При выборе между parfor
, parfeval
, и spmd
, учитывайте, требует ли ваше вычисление синхронизации с клиентом.
parfor
и spmd
требовать синхронизации и поэтому блокировать выполнение новых расчетов на MATLAB® клиент. parfeval
не требует синхронизации, поэтому клиент может свободно выполнять другую работу.
ProcessPool
В этом примере вы сравниваете, как быстро функции выполняются на клиенте и на ProcessPool
. Некоторые функции MATLAB используют многопоточность. Задачи, которые используют эти функции, работают с несколькими потоками лучше, чем с одним потоком. Поэтому, если вы используете эти функции на машине с множеством ядер, локальный кластер может работать хуже, чем многопоточность на клиенте.
Вспомогательная функция clientFasterThanPool
, перечисленный в конце этого примера, возвращает true
если множества потоков выполнения выполняются на клиенте быстрее, чем на parfor
-цикл. Синтаксис такой же, как parfeval
: используйте указатель на функцию в качестве первого аргумента, количество выходов в качестве второго аргумента, а затем передайте все необходимые аргументы для функции.
Во-первых, создайте локальную ProcessPool
.
p = parpool('local');
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 6).
Проверяйте, насколько быстро eig
функция выполняется при помощи clientFasterThanPool
вспомогательная функция. Создайте анонимную функцию с eig
чтобы представлять ваш вызов функции.
[~, t_client, t_pool] = clientFasterThanPool(@(N) eig(randn(N)), 0, 500)
t_client = 22.6243
t_pool = 4.9334
Параллельный пул вычисляет ответ быстрее, чем клиент. Разделите t_client
по maxNumCompThreads
чтобы найти время, затрачиваемое на каждый поток на клиенте.
t_client/maxNumCompThreads
ans = 3.7707
Рабочие по умолчанию имеют одну резьбу. Результат указывает, что время, затраченное на каждый поток, совпадает как с клиентом, так и с пулом, так и со значением t_pool
примерно в 1,5 раза больше значения t_client/maxNumCompThreads
. The eig
функция не выигрывает от многопоточности.
Далее проверьте, насколько быстро lu
функция выполняется при помощи clientFasterThanPool
вспомогательная функция.
[~, t_client, t_pool] = clientFasterThanPool(@(N) lu(randn(N)), 0, 500)
t_client = 1.0225
t_pool = 0.4693
Параллельный пул обычно вычисляет ответ быстрее, чем клиент, если локальный компьютер имеет четыре или более ядра. Разделите t_client
по maxNumCompThreads
чтобы найти время, затрачиваемое на каждый поток.
t_client/maxNumCompThreads
ans = 0.1704
Этот результат указывает, что время, затраченное на каждый поток, на клиенте намного меньше, чем на пул, так как значение t_pool
примерно в 3 раза больше, чем значение t_client/maxNumCompThreads
. Каждый поток используется в течение меньшего вычислительного времени, что указывает на то, что lu
использует многопоточность.
Определите функцию помощника
Вспомогательная функция clientFasterThanPool
проверяет, является ли расчет более быстрым для клиента, чем для параллельного пула. Он принимает за вход указатель на функцию fcn
и переменное число входных параметров (in1, in2, ...
). clientFasterThanPool
выполняет fcn(in1, in2, ...)
как в клиенте, так и в активном параллельном пуле. В качестве примера, если вы хотите протестировать rand(500)
, указатель на функцию должен быть в следующей форме:
fcn = @(N) rand(N);
Затем используйте clientFasterThanPool(fcn,500)
.
function [result, t_multi, t_single] = clientFasterThanPool(fcn,numout,varargin) % Preallocate cell array for outputs outputs = cell(numout); % Client tic for i = 1:200 if numout == 0 fcn(varargin{:}); else [outputs{1:numout}] = fcn(varargin{:}); end end t_multi = toc; % Parallel pool vararginC = parallel.pool.Constant(varargin); tic parfor i = 1:200 % Preallocate cell array for outputs outputs = cell(numout); if numout == 0 fcn(vararginC.Value{:}); else [outputs{1:numout}] = fcn(vararginC.Value{:}); end end t_single = toc; % If multhreading is quicker, return true result = t_single > t_multi; end
parfor
, parfeval
, и spmd
Использование spmd
может быть медленнее или быстрее, чем использование parfor
-циклы или parfeval
, в зависимости от типа расчетов. Накладные расходы влияют на относительную эффективность parfor
-циклы, parfeval
, и spmd
.
Для набора задач, parfor
и parfeval
обычно выполняйте лучше spmd
в этих условиях.
Вычислительное время, затраченное на задачу, не детерминировано.
Вычислительное время, затраченное на задачу, неоднородно.
Данные, возвращенные из каждой задачи, малы.
Использование parfeval
когда:
Вы хотите запустить расчеты в фоновом режиме.
Каждая задача зависит от других задач.
В этом примере вы исследуете скорость, с которой можно выполнить матричные операции при использовании parfor
-цикл, parfeval
, и spmd
.
Сначала создайте локальный параллельный пул p
.
p = parpool('local');
Starting parallel pool (parpool) using the 'local' profile ... Connected to the parallel pool (number of workers: 6).
Вычисление случайных матриц
Исследуйте скорость, с которой случайные матрицы могут быть сгенерированы при помощи parfor
-цикл, parfeval
, и spmd
. Установите количество испытаний (n
) и размер матрицы (для m
-by- m
матрица). Увеличение количества испытаний улучшает статистику, используемую в последующем анализе, но не влияет на сам расчет.
m = 1000; n = 20;
Затем используйте parfor
-цикл, чтобы выполнить rand(m)
один раз для каждого работника. Время каждого из n
судебные разбирательства.
parforTime = zeros(n,1); for i = 1:n tic; mats = cell(1,p.NumWorkers); parfor N = 1:p.NumWorkers mats{N} = rand(m); end parforTime(i) = toc; end
Далее используйте parfeval
для выполнения rand(m)
один раз для каждого работника. Время каждого из n
судебные разбирательства.
parfevalTime = zeros(n,1); for i = 1:n tic; f(1:p.NumWorkers) = parallel.FevalFuture; for N = 1:p.NumWorkers f(N) = parfeval(@rand,1,m); end mats = fetchOutputs(f, "UniformOutput", false)'; parfevalTime(i) = toc; clear f end
Наконец, используйте spmd
для выполнения rand(m)
один раз для каждой лаборатории. Для получения дополнительной информации о лабораториях и как выполнять команды на них с spmd
, см. «Запуск одиночных программ на нескольких наборах данных». Время каждого из n
судебные разбирательства.
spmdTime = zeros(n,1); for i = 1:n tic; spmd e = rand(m); end eigenvals = {e{:}}; spmdTime(i) = toc; end
Использование rmoutliers
чтобы удалить выбросы из каждого из испытаний. Затем используйте boxplot
сравнить время.
% Hide outliers boxData = rmoutliers([parforTime parfevalTime spmdTime]); % Plot data boxplot(boxData, 'labels',{'parfor','parfeval','spmd'}, 'Symbol','') ylabel('Time (seconds)') title('Make n random matrices (m by m)')
Как правило, spmd
требуется больше накладных расходов на оценку, чем parfor
или parfeval
. Поэтому в этом случае использование parfor
-цикл или parfeval
является более эффективным.
Вычисление суммы случайных матриц
Затем вычислите сумму случайных матриц. Вы можете сделать это с помощью переменной сокращения с parfor
-цикл, сумма после расчетов с parfeval
, или gplus
с spmd
. Снова установите количество испытаний (n
) и размер матрицы (для m
-by- m
матрица).
m = 1000; n = 20;
Затем используйте parfor
-цикл, чтобы выполнить rand(m)
один раз для каждого работника. Вычислите сумму с переменной сокращения. Время каждого из n
судебные разбирательства.
parforTime = zeros(n,1); for i = 1:n tic; result = 0; parfor N = 1:p.NumWorkers result = result + rand(m); end parforTime(i) = toc; end
Далее используйте parfeval
для выполнения rand(m)
один раз для каждого работника. Использование fetchOutputs
на всех матрицах, затем используйте sum
. Время каждого из n
судебные разбирательства.
parfevalTime = zeros(n,1); for i = 1:n tic; f(1:p.NumWorkers) = parallel.FevalFuture; for N = 1:p.NumWorkers f(N) = parfeval(@rand,1,m); end result = sum(fetchOutputs(f)); parfevalTime(i) = toc; clear f end
Наконец, используйте spmd
для выполнения rand(m)
один раз для каждой лаборатории. Использование gplus
для суммирования всех матриц. Чтобы отправить результат только в первую лабораторию, установите дополнительное targetlab
аргумент в 1
. Время каждого из n
судебные разбирательства.
spmdTime = zeros(n,1); for i = 1:n tic; spmd r = gplus(rand(m), 1); end result = r{1}; spmdTime(i) = toc; end
Использование rmoutliers
чтобы удалить выбросы из каждого из испытаний. Затем используйте boxplot
сравнить время.
% Hide outliers boxData = rmoutliers([parforTime parfevalTime spmdTime]); % Plot data boxplot(boxData, 'labels',{'parfor','parfeval','spmd'}, 'Symbol','') ylabel('Time (seconds)') title('Sum of n random matrices (m by m)')
Для этого вычисления spmd
значительно быстрее, чем parfor
-цикл или parfeval
. Когда вы используете переменные сокращения в parfor
-цикл, вы транслируете результат каждой итерации parfor
-крыть всем рабочим. Напротив, spmd
вызывает gplus
только один раз, чтобы выполнить глобальную операцию сокращения, требующую меньших накладных расходов. Таким образом, накладные расходы для части сокращения вычисления для spmd
, и для parfor
.