Выполняйте функцию асинхронно на работнике параллельного пула
запрашивает асинхронное выполнение функции F
= parfeval(p
,fcn
,numout
,in1,in2,...
)fcn
на работнике, содержащемся в параллельном пуле p
, ожидая numout
выходные аргументы и предоставление в качестве входных параметров in1,in2,...
. Асинхронная оценка fcn
не блокирует MATLAB. F
является parallel.FevalFuture
объект, из которого могут быть получены результаты, когда рабочий выполнил оценку fcn
. Оценка fcn
всегда выполняется, если вы явным образом не отменяете выполнение путем вызова cancel(F)
. Чтобы запросить несколько вычислений функции, необходимо вызвать parfeval
несколько раз. (Однако parfevalOnAll
может выполнять ту же функцию для всех работников.)
запрашивает асинхронное выполнение в текущем параллельном пуле. Если пул не существует, он запускает новый параллельный пул, если только ваши параллельные настройки не отключают автоматическое создание пулов.F
= parfeval(fcn
,numout
,in1,in2,...
)
parfeval
ФьючерсыКогда вы используете parfeval
или parfevalOnAll
чтобы запустить расчеты в фоновом режиме, вы создаете объекты под названием futures. Можно использовать 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
. The RunningFutures
свойство является массивом фьючерсов, соответствующих текущим задачам.
disp(p.FevalQueue.RunningFutures)
1x2 FevalFuture array: ID State FinishDateTime Function Error -------------------------------------------------------- 1 12 running @pause 2 15 running @pause
The 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);
Можно также отправить вектор из нескольких будущих запросов в 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
В этом примере показано, как выполнить сдвиг параллельного параметра с parfeval
и отправьте результаты назад во время расчетов с DataQueue
объект. parfeval
не блокирует MATLAB, поэтому можно продолжать работу во время выполнения расчетов.
Пример выполняет свип параметра на системе Лоренца обыкновенных дифференциальных уравнений, на параметрах и , и показывает хаотичность этой системы.
Создайте сетку параметров
Задайте область значений параметров, которые вы хотите исследовать в сдвиге параметра.
gridSize = 40; sigma = linspace(5, 45, gridSize); rho = linspace(50, 100, gridSize); beta = 8/3;
Создайте 2-D сетку параметров при помощи 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
функция. The 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')
Если вашему параметру sweep нужно больше вычислительных ресурсов и у вас есть доступ к кластеру, можно масштабировать 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
afterEach
и afterAll
В этом примере показано, как обновить пользовательский интерфейс по мере завершения расчетов. Когда вы разгружаете расчеты рабочим, использующим parfeval
все пользовательские интерфейсы являются быстрыми, в то время как работники выполняют эти расчеты. В этом примере вы используете waitbar
для создания простого пользовательского интерфейса.
Использование afterEach
обновлять пользовательский интерфейс после завершения каждого расчета.
Использование afterAll
обновить пользовательский интерфейс после завершения расчетов.
Использование waitbar
чтобы создать указатель на рисунок, h
. Когда вы используете afterEach
или afterAll
, а waitbar
функция обновляет указатель на рисунок. Для получения дополнительной информации об указателе объектов смотрите Указатель Объекта Behavior.
h = waitbar(0,'Waiting...');
Использование parfeval
вычислить вещественную часть собственных значений случайных матриц. С настройками по умолчанию parfeval
автоматически создает параллельный пул, если он еще не создан.
for idx = 1:100 f(idx) = parfeval(@(n) real(eig(randn(n))),1,5e2); end
Можно использовать afterEach
для автоматического вызова функций на каждом из результатов parfeval
расчеты. Использование afterEach
вычислять самое большое значение в каждом из выходных массивов после завершения каждого будущего.
maxFuture = afterEach(f,@max,1);
Можно использовать State
свойство для получения статуса фьючерса. Создайте логический массив, где State
свойство фьючерсов в f
является "finished"
. Использование mean
вычислить долю готовых фьючерсов. Затем создайте анонимную функцию updateWaitbar
. Функция изменяет дробную длину полосы ожидания h
к части готовых фьючерсов.
updateWaitbar = @(~) waitbar(mean({f.State} == "finished"),h);
Использование afterEach
и updateWaitbar
чтобы обновить дробную длину полосы ожидания после каждого будущего в maxFuture
завершает. Использование afterAll
и delete
чтобы закрыть панель ожидания после завершения всех расчетов.
updateWaitbarFutures = afterEach(f,updateWaitbar,0); afterAll(updateWaitbarFutures,@(~) delete(h),0);
Использование afterAll
и histogram
чтобы показать гистограмму результатов в maxFuture
после завершения всех фьючерсов.
showsHistogramFuture = afterAll(maxFuture,@histogram,0);
p
- Параллельный пулparallel.Pool
объектПараллельный пул рабочих, заданный как parallel.Pool
объект. Вы можете создать параллельный пул при помощи parpool
функция.
Типы данных: parallel.Pool
fcn
- Функция для выполненияФункция для выполнения на рабочем месте, заданная как указатель на функцию.
Пример: fcn = @sum
Типы данных: function_handle
numout
- Количество выходных аргументовКоличество выходных аргументов, ожидаемых от fcn
.
Типы данных: single
| double
| int8
| int16
| int32
| int64
| uint8
| uint16
| uint32
| uint64
in1,in2,...
- Аргументы функцииАргументы функции, которые передаются в fcn
, заданный как разделенный запятыми список переменных или выражений.
F
- Будущееparallel.FevalFuture
Объект будущего, возвращенный как parallel.FevalFuture
, что представляет собой выполнение fcn
на параллельном рабочем и проводит его результаты. Использовать fetchOutputs
или fetchNext
для сбора результатов.
afterAll
| afterEach
| cancel
| fetchNext
| fetchOutputs
| Future
| isequal
| parallel.pool.Constant
| parfevalOnAll
| parpool
| ticBytes
| tocBytes
| wait
У вас есть измененная версия этого примера. Вы хотите открыть этот пример с вашими правками?
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.