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.
You can find the code shown in this example in the function:
Analyze the sequential problem
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;
Divide the work into individual function evaluations
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_blackjackview 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));
Starting parallel pool (parpool) using the 'MJS' profile ... connected to 12 workers.
Set up for collecting results and monitoring progress
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);
Collect and display results as they become available
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
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: 28