Выбор между 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 только один раз, чтобы выполнить глобальную операцию сокращения, требующую меньших накладных расходов. Таким образом, накладные расходы для части сокращения вычисления O(n2) для spmd, и O(mn2) для parfor.

См. также

| |

Похожие темы