Блэк джек Parfeval

Этот пример использует Parallel Computing Toolbox™, чтобы проигрывать карточную игру блэк джека, также известного 21. Мы моделируем много проигрывателей, которые независимо проигрывают тысячи рук за один раз и статистики выплаты отображения. Этот пример запускает симуляции асинхронно на параллельном пуле рабочих, с помощью parfeval. Таким образом мы можем обновить отображение результатов, когда они становятся доступными.

Связанные примеры:

Можно найти код показанным в этом примере в функции:

function paralleldemo_blackjack_parfeval

Анализируйте последовательную проблему

Поскольку проигрыватели блэк джека независимы друг от друга, мы можем моделировать их параллельно. Мы делаем это путем деления проблемы на многие функциональные оценки. Мы запускаем максимум симуляций numPlayers, где каждый игрок проигрывает руки numHands блэк джека. Мы строим результаты, как только они становятся доступными, и мы отключаем симуляцию, если прошедшее время превышает секунды maxSimulationTime, или если пользователь отменяет выполнение.

numPlayers        = 100;
numHands          = 5000;
maxSimulationTime = 20;

Разделите работу на отдельные функциональные оценки

Мы вызываем функцию parfeval, чтобы запросить оценку симуляции на параллельных рабочих пула. Параллельный пул будет автоматически создан при необходимости. Функция parfeval возвращает объект parallel.Future, который мы используем для результатов доступа, когда они становятся доступными. Можно просмотреть код для pctdemo_task_blackjack для полного изложения.

for idx = numPlayers:-1:1
    futures(idx) = parfeval(@pctdemo_task_blackjack, 1, numHands, 1);
end
% Create an onCleanup to ensure we do not leave any futures running when we exit
% this example.
cancelFutures = onCleanup(@() cancel(futures));

Настройте для сбора результатов и контроля прогресса

Параллельные рабочие пула сразу начинают запускать pctdemo_task_blackjack, и мы можем собрать и отобразить результаты, как только они доступны при помощи метода fetchNext. Мы используем resultsSoFar, чтобы накопить результаты. Мы обновляем массив completed, чтобы указать, какие элементы futures завершились и постепенно увеличивают встречный numCompleted. Мы предоставляем дополнительный аргумент timeout к методу fetchNext так, чтобы это возвратилось быстро, если никакие новые результаты не доступны.

resultsSoFar = zeros(numHands, numPlayers); % Allocate space for all results
completed    = false(1, numPlayers);        % Has a given future completed yet
timeout      = 2;                           % fetchNext timeout in seconds
numCompleted = 0;                           % How many simulations have completed
fig          = pctdemo_setup_blackjack(1);  % Create a figure to display results

% Build a waitbar with a cancel button, using appdata to track
% whether the cancel button has been pressed.
hWaitBar = waitbar(0, 'Blackjack progress', 'CreateCancelBtn', ...
                   @(src, event) setappdata(gcbf(), 'Cancelled', true));
setappdata(hWaitBar, 'Cancelled', false);

Соберите и отобразите результаты, когда они становятся доступными

Мы собираем и отображаем результаты путем вызова fetchNext в цикле, пока мы не видели результаты numPlayers. Когда fetchNext возвращает новые результаты, мы присваиваем результаты в resultsSoFar, обновляем массив completed и счетчик numCompleted, и обновляем график. Мы прерываем цикл рано, если пользователь нажимает кнопку отмены на waitbar, или maxSimulationTime истекает.

startTime = clock();
while numCompleted < numPlayers

    % fetchNext blocks execution until one element of futures has completed.  It
    % then returns the index into futures of the element that has now completed,
    % and the results from execution.
    [completedIdx, resultThisTime] = fetchNext(futures, timeout);

    % If fetchNext timed out returning an empty completedIdx, do not attempt to
    % process results.
    if ~isempty(completedIdx)
        numCompleted = numCompleted + 1;
        % Update list of completed futures.
        completed(completedIdx) = true;
        % Fill out portion of results.
        resultsSoFar(:, completedIdx) = resultThisTime;
        % Update plot.
        pctdemo_plot_blackjack(fig, resultsSoFar(:, completed), false);
    end

    % Check to see if we have run out of time.
    timeElapsed = etime(clock(), startTime);
    if timeElapsed > maxSimulationTime
        fprintf('Simulation terminating: maxSimulationTime exceeded.\n');
        break;
    end

    % Check to see if the cancel button was pressed.
    if getappdata(hWaitBar, 'Cancelled')
        fprintf('Simulation cancelled.\n');
        break;
    end

    % Update the waitbar.
    fractionTimeElapsed      = timeElapsed / maxSimulationTime;
    fractionPlayersCompleted = numCompleted / numPlayers;
    fractionComplete         = max(fractionTimeElapsed, fractionPlayersCompleted);
    waitbar(fractionComplete, hWaitBar);
end
fprintf('Number of simulations completed: %d\n', numCompleted);

% Now the simulation is complete, we can cancel the futures and delete
% the waitbar.
cancel(futures);
delete(hWaitBar);
Simulation terminating: maxSimulationTime exceeded.
Number of simulations completed: 74

end