This example uses Parallel Computing Toolbox™ to play the card game of blackjack, also known as 21. We simulate a number of players that are independently playing thousands of hands at a time, and display payoff statistics. This example runs the simulations asynchronously on a parallel pool of workers, using parfeval
. In this way, we can update a display of the results as they become available.
Related examples:
You can find the code shown in this example in the function:
function paralleldemo_blackjack_parfeval
Because the blackjack players are independent of one another, we can simulate them in parallel. We do this by dividing the problem up into a number of function evaluations. We run a maximum of numPlayers
simulations, where each player plays numHands
hands of blackjack. We plot the results as soon as they become available, and we terminate the simulation if the elapsed time exceeds maxSimulationTime
seconds, or if the user cancels execution.
numPlayers = 100; numHands = 5000; maxSimulationTime = 20;
We call the parfeval
function to request evaluation of the simulation on the parallel pool workers. The parallel pool will be created automatically if necessary. The parfeval
function returns a parallel.Future
object, which we use to access results when they become available. You can view the code for pctdemo_task_blackjack for full details.
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));
The parallel pool workers immediately start running pctdemo_task_blackjack
, and we can collect and display results as soon as they are available by using the fetchNext
method. We use resultsSoFar
to accumulate results. We update the array completed
to indicate which elements of futures
have completed, and increment the counter numCompleted
. We supply the optional argument timeout
to the fetchNext
method so that it returns quickly if no new results are available.
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);
We collect and display results by calling fetchNext
in a loop until we have seen numPlayers
results. When fetchNext
returns new results, we assign the results into resultsSoFar
, update the completed
array and the numCompleted
counter, and update the plot. We abort the loop early if the user presses the cancel button on the waitbar, or the maxSimulationTime
expires.
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