parfeval

Выполните функцию асинхронно на параллельном рабочем пула

Описание

пример

F = parfeval(p,fcn,numout,in1,in2,...) запрашивает асинхронное выполнение функционального fcn на рабочем, содержавшемся в параллельном пуле p, ожидание numout выходные аргументы и предоставляющий как входные параметры in1,in2,.... Асинхронная оценка fcn не делает блока MATLAB. F параллель. Объект FevalFuture, из которого могут быть получены результаты, когда рабочий завершил оценку fcn. Оценка fcn всегда доходы, если вы явным образом не отменяете выполнение путем вызова cancel(F). Чтобы запросить несколько вычислений функции, необходимо вызвать parfeval многократно. (Однако parfevalOnAll может запустить ту же функцию на всех рабочих.)

пример

F = parfeval(fcn,numout,in1,in2,...) запрашивает асинхронное выполнение на текущем параллельном пуле. Если никакой пул не существует, это запускает новый параллельный пул, если ваши параллельные настройки не отключают автоматическое создание пулов.

Примеры

свернуть все

Когда вы используете parfeval или parfevalOnAll чтобы запустить расчеты в фоновом режиме, вы создаете названные фьючерсы объектов. Можно использовать State свойство будущего узнать, запускается ли это, поставленный в очередь или законченный. Можно также использовать FevalQueue свойство параллельного пула к выполнению доступа и поставленным в очередь фьючерсам. Чтобы отменить фьючерсы, можно использовать cancel функция. В этом примере, вас:

  • Используйте cancel отменять фьючерсы непосредственно.

  • Проверяйте ошибки завершения на завершенных фьючерсах.

  • Используйте FevalQueue свойство получить доступ к фьючерсам.

Добавьте работу в очередь

Создайте параллельный пул p с двумя рабочими.

p = parpool(2);
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 2).

Когда вы используете parfeval чтобы запустить расчеты в фоновом режиме, функция создает и добавляет будущее для каждого расчета очереди пула. Задачи остаются в очереди, пока рабочий не становится неактивным. Когда рабочий становится неактивным, это начинает вычислять задачу, если очередь не пуста. Когда рабочий выполняет задачу, задача удалена из очереди, и рабочий становится неактивным.

Используйте parfeval создать массив фьючерсов f давая рабочим команду выполнить функциональный pause. Используйте аргумент 1 для третьего будущего и аргумента Inf для всех других фьючерсов.

for n = 1:5
    if n == 3
        f(n) = parfeval(@pause,0,1);
    else
        f(n) = parfeval(@pause,0,Inf);
    end
end

Каждое использование parfeval возвращает будущий объект, который представляет выполнение функции на рабочем. За исключением третьего будущего, каждое будущее займет бесконечное количество времени, чтобы вычислить. Будущее создается parfeval(@pause,0,Inf) крайний случай будущего, которое может замедлить очередь.

Отмените фьючерсы непосредственно

Можно использовать State свойство получить состояние фьючерсов. Создайте массив ячеек состояния каждого будущего в f.

{f.State}
ans = 1×5 cell
    {'running'}    {'running'}    {'queued'}    {'queued'}    {'queued'}

Каждая задача за исключением трети делает паузу навсегда.

Отмените второе будущее непосредственно с cancel.

cancel(f(2));
{f.State}
ans = 1×5 cell
    {'running'}    {'finished'}    {'running'}    {'queued'}    {'queued'}

После того, как вы отменяете второе будущее, третьи будущие запуски. Ожидайте, пока третье будущее не завершается, затем исследуйте состояния снова.

wait(f(3));
{f.State}
ans = 1×5 cell
    {'running'}    {'finished'}    {'finished'}    {'running'}    {'queued'}

Третье будущее теперь имеет 'finished' состояния.

Проверяйте ошибки завершения

Когда будущее завершается, его State свойство становится 'finished'. Чтобы различать фьючерсы, которые отменяются и обычно завершаются, используйте Error свойство.

fprintf("f(2): %s\n", f(2).Error.message)
f(2): Execution of the future was cancelled.
fprintf("f(3): %s\n", f(3).Error.message)
f(3): 

Код отменяет второе будущее, как свойство сообщения указывает. Второе будущее было отменено, как утверждено в message свойство. Третье будущее завершается без ошибки, и поэтому не имеет сообщения об ошибке.

Отмените фьючерсы в очереди пула

Можно использовать FevalQueue свойство получить доступ к фьючерсам в очереди пула.

p.FevalQueue
ans = 
 FevalQueue with properties: 

        Number Queued: 1
       Number Running: 2

У очереди есть два свойства: RunningFutures и QueuedFutures. RunningFutures свойство является массивом фьючерсов, соответствуя задачам, которые в настоящее время запускаются.

disp(p.FevalQueue.RunningFutures)
 1x2 FevalFuture array:
 
         ID              State  FinishDateTime  Function  Error
       --------------------------------------------------------
    1    12            running                    @pause       
    2    15            running                    @pause       

QueuedFutures свойство является массивом фьючерсов, соответствуя задачам, которые в настоящее время ставятся в очередь и не выполнение.

disp(p.FevalQueue.QueuedFutures)
 FevalFuture with properties: 

                   ID: 16
             Function: @pause
       CreateDateTime: 15-Jul-2020 17:29:37
        StartDateTime: 
     Running Duration: 0 days 0h 0m 0s
                State: queued
                Error: none

Можно отменить одно будущее или массив фьючерсов. Отмените все фьючерсы в QueuedFutures.

cancel(p.FevalQueue.QueuedFutures);
{f.State}
ans = 1×5 cell
    {'running'}    {'finished'}    {'finished'}    {'running'}    {'finished'}

RunningFutures и QueuedFutures сортируются от самых старых до новейших, независимо от ли f в порядке от самых старых до новейших. Каждое будущее имеет уникальный ID свойство в течение времени жизни клиента. Проверяйте ID свойство каждых из фьючерсов в f.

disp(f)
 1x5 FevalFuture array:
 
         ID              State        FinishDateTime  Function  Error
       --------------------------------------------------------------
    1    12            running                          @pause       
    2    13  finished (unread)  15-Jul-2020 17:29:37    @pause  Error
    3    14  finished (unread)  15-Jul-2020 17:29:39    @pause       
    4    15            running                          @pause       
    5    16  finished (unread)  15-Jul-2020 17:29:39    @pause  Error

Сравните результат с ID свойство каждого RunningFutures.

for j = 1:length(p.FevalQueue.RunningFutures)
    rf = p.FevalQueue.RunningFutures(j);
    fprintf("p.FevalQueue.RunningFutures(%i): ID = %i\n", j, rf.ID)
end
p.FevalQueue.RunningFutures(1): ID = 12
p.FevalQueue.RunningFutures(2): ID = 15

Здесь, RunningFutures массив, содержащий f(1) и f(4). Если вы отменяете RunningFutures(2), вы отменяете четвертый будущий f(4).

Иногда, фьючерсы не доступны в рабочей области, например, если вы выполняете ту же часть кода дважды, прежде чем это закончится, или если вы используете parfeval в функции. Можно отменить фьючерсы, которые не доступны в рабочей области.

Очистите f из рабочей области.

clear f

Можно использовать RunningFutures и QueuedFutures к фьючерсам доступа, которые еще не завершились. Используйте RunningFutures отменять f(4).

rf2 = p.FevalQueue.RunningFutures(2);
cancel(rf2)
rf2.State
ans = 
'finished'

Чтобы отменить все фьючерсы все еще в очереди, используйте следующий код.

cancel([p.FevalQueue.RunningFutures p.FevalQueue.QueuedFutures])

Использование parfeval запрашивать асинхронное выполнение функции на рабочем.

Например, отправьте один запрос к параллельному пулу. Получите выходные параметры при помощи fetchOutputs.

f = parfeval(@magic,1,10);
value = fetchOutputs(f);

Можно также представить вектор из нескольких будущих запросов в a for- цикл и собирает результаты, когда они становятся доступными. Для КПД предварительно выделите массив будущих объектов прежде.

f(1:10) = parallel.FevalFuture;
for idx = 1:10
    f(idx) = parfeval(@magic,1,idx);
end

Получите отдельные будущие выходные параметры, когда они становятся доступными при помощи fetchNext.

magicResults = cell(1,10);
for idx = 1:10
    [completedIdx,value] = fetchNext(f);
    magicResults{completedIdx} = value;
    fprintf('Got result with index: %d.\n', completedIdx);
end

В этом примере показано, как выполнить параллельную развертку параметра с parfeval и передайте результаты обратно во время расчетов с DataQueue объект. parfeval не делает блока MATLAB, таким образом, можно продолжить работать, в то время как расчеты происходят.

Пример выполняет развертку параметра в системе Лоренца обыкновенных дифференциальных уравнений на параметрах σ и ρ, и показывает хаотическую природу этой системы.

ddtx=σ(y-z)ddty=x(ρ-z)-yddtz=xy-βx

Создайте сетку параметра

Задайте область значений параметров, которые вы хотите исследовать в развертке параметра.

gridSize = 40;
sigma = linspace(5, 45, gridSize);
rho = linspace(50, 100, gridSize);
beta = 8/3;

Создайте 2D сетку параметров при помощи meshgrid функция.

[rho,sigma] = meshgrid(rho,sigma);

Создайте объект фигуры и установите 'Visible' к true так, чтобы это открылось в новом окне, за пределами live скрипта. Чтобы визуализировать результаты развертки параметра, создайте объемную поверхностную диаграмму. Обратите внимание на то, что инициализация Z компонент поверхности с NaN создает пустой график.

figure('Visible',true);
surface = surf(rho,sigma,NaN(size(sigma)));
xlabel('\rho','Interpreter','Tex')
ylabel('\sigma','Interpreter','Tex')

Настройте параллельную среду

Создайте пул параллельных рабочих при помощи parpool функция.

parpool;
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 6).

Чтобы отправить данные от рабочих, создайте DataQueue объект. Настройте функцию, которая обновляет объемную поверхностную диаграмму каждый раз, когда рабочий отправляет данные при помощи afterEach функция. updatePlot функция является функцией, определяемой поддержки в конце примера.

Q = parallel.pool.DataQueue;
afterEach(Q,@(data) updatePlot(surface,data));

Выполните параллельную развертку параметра

После того, как вы зададите параметры, можно выполнить параллельную развертку параметра.

parfeval работает более эффективно, когда вы распределяете рабочую нагрузку. Чтобы распределить рабочую нагрузку, сгруппируйте параметры, чтобы исследовать в разделы. В данном примере разделите в универсальные разделы размера step при помощи оператора двоеточия (:). Полученный массив partitions содержит контуры разделов. Обратите внимание на то, что необходимо добавить конечную точку последнего раздела.

step = 100;
partitions = [1:step:numel(sigma), numel(sigma)+1]
partitions = 1×17

           1         101         201         301         401         501         601         701         801         901        1001        1101        1201        1301        1401        1501        1601

Для лучшей эффективности попытайтесь разделить в разделы, которые являются:

  • Достаточно большой, что время вычисления является большим по сравнению с издержками планирования раздела.

  • Достаточно маленький, что существует достаточно разделов, чтобы заставить всех рабочих напряженно трудиться.

Чтобы представлять функциональное выполнение на параллельных рабочих и содержать их результаты, используйте будущие объекты.

f(1:numel(partitions)-1) = parallel.FevalFuture;

Разгрузите расчеты, чтобы быть параллельными рабочим при помощи parfeval функция. parameterSweep функция, определяемая помощника в конце этого скрипта, который решает систему Лоренца на разделе параметров, чтобы исследовать. Это имеет один выходной аргумент, таким образом, необходимо задать 1 как количество выходных параметров в parfeval.

for ii = 1:numel(partitions)-1
    f(ii) = parfeval(@parameterSweep,1,partitions(ii),partitions(ii+1),sigma,rho,beta,Q);
end

parfeval не делает блока MATLAB, таким образом, можно продолжить работать, в то время как расчеты происходят. Рабочие вычисляют параллельно и отправляют промежуточные результаты через DataQueue как только они становятся доступными.

Если вы хотите с блоком MATLAB до parfeval завершается, используйте wait функция на будущих объектах. Используя wait функция полезна, когда последующий код зависит от завершения parfeval.

wait(f);

После parfeval закончил расчеты, wait концы и вы можете выполнить больше кода. Например, постройте контур получившейся поверхности. Используйте fetchOutputs функция, чтобы получить результаты, сохраненные в будущих объектах.

results = reshape(fetchOutputs(f),gridSize,[]);
contourf(rho,sigma,results)
xlabel('\rho','Interpreter','Tex')
ylabel('\sigma','Interpreter','Tex')

Если вашей развертке параметра нужно больше вычислительных ресурсов, и у вас есть доступ к кластеру, можно увеличить parfeval расчеты. Для получения дополнительной информации смотрите, Масштабируют от Рабочего стола до Кластера.

Определение функций помощника

Задайте функцию помощника, которая решает систему Лоренца на разделе параметров, чтобы исследовать. Отправьте промежуточные результаты клиенту MATLAB при помощи send функция на DataQueue объект.

function results = parameterSweep(first,last,sigma,rho,beta,Q)
    results = zeros(last-first,1);
    for ii = first:last-1
        lorenzSystem = @(t,a) [sigma(ii)*(a(2) - a(1)); a(1)*(rho(ii) - a(3)) - a(2); a(1)*a(2) - beta*a(3)];
        [t,a] = ode45(lorenzSystem,[0 100],[1 1 1]);
        result = a(end,3);
        send(Q,[ii,result]);
        results(ii-first+1) = result;
    end
end

Задайте другую функцию помощника, которая обновляет объемную поверхностную диаграмму, когда новые данные прибывают.

function updatePlot(surface,data)
    surface.ZData(data(1)) = data(2);
    drawnow('limitrate');
end

Можно выполнить асинхронные расчеты на рабочих, использующих parfeval и оставьте пользовательский интерфейс быстро реагирующим. Используйте afterEach обновить пользовательский интерфейс, когда промежуточные расчеты готовы. Используйте afterAll обновить пользовательский интерфейс, когда все расчеты готовы.

Создайте простой пользовательский интерфейс с помощью waitbar.

h = waitbar(0, 'Waiting...');

Используйте parfeval выполнить длительные расчеты в рабочих, например, собственных значениях случайных матриц. Расчеты происходят асинхронно и обновления пользовательского интерфейса во время расчета. С настройками по умолчанию, parfeval создает parpool автоматически, если нет того, уже созданного.

for idx = 1:100
    f(idx) = parfeval(@(n) real(eig(randn(n))), 1, 5e2); 
end

Вычислите самое большое значение в каждом из расчетов, когда они станут готовым использованием afterEach. Обновите пропорцию законченных фьючерсов в waitbar, когда каждый из них завершит использование afterEach.

maxFuture = afterEach(f, @max, 1);
updateWaitbarFuture = afterEach(f, @(~) waitbar(sum(strcmp('finished', {f.State}))/numel(f), h), 1);

Закройте waitbar, когда все расчеты будут сделаны. Используйте afterAll на updateWaitbarFuture продолжаться автоматически операцией закрытия. afterAll получает указатель фигуры из updateWaitbarFuture и выполняет его функцию на нем.

closeWaitbarFuture = afterAll(updateWaitbarFuture, @(h) delete(h), 0);

Покажите гистограмму после того, как все максимальные значения будут вычислены. Используйте afterAll на maxFuture продолжать операцию автоматически. afterAll получает максимальные значения из maxFuture и вызовы histogram на них.

showsHistogramFuture = afterAll(maxFuture, @histogram, 0);

Входные параметры

свернуть все

Параллельный пул рабочих в виде parallel.Pool объект. Можно создать параллельный пул при помощи parpool функция.

Типы данных: parallel.Pool

Функция, чтобы выполниться на рабочем в виде указателя на функцию.

Пример: fcn = @sum

Типы данных: function_handle

Количество выходных аргументов, которые ожидаются от fcn.

Типы данных: single | double | int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64

Аргументы функции, чтобы передать fcnВ виде списка, разделенного запятыми переменных или выражений.

Выходные аргументы

свернуть все

Будущий объект, возвращенный как parallel.FevalFuture, это представляет выполнение fcn на параллельном рабочем и содержит его результаты. Использование fetchOutputs или fetchNext собрать результаты.

Введенный в R2013b