Main Content

Query and Cancel parfeval Futures

When you use parfeval or parfevalOnAll to run computations in the background, you create objects called futures. You can use the State property of a future to find out whether it is running, queued or finished. You can also use the FevalQueue property of a parallel pool to access running and queued futures. To cancel futures, you can use the cancel function. In this example, you:

  • Use cancel to cancel futures directly.

  • Check completion errors on completed futures.

  • Use the FevalQueue property to access futures.

Add Work to Queue

Create a parallel pool p with two workers.

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

When you use parfeval to run computations in the background, the function creates and adds a future for each computation to the pool queue. Tasks remain in the queue until a worker becomes idle. When a worker becomes idle, it starts to compute a task if the queue is not empty. When a worker completes a task, the task is removed from the queue and the worker becomes idle.

Use parfeval to create an array of futures f by instructing workers to execute the function pause. Use an argument of 1 for the third future, and an argument of Inf for all other futures.

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

Each use of parfeval returns a future object that represents the execution of a function on a worker. Except for the third future, every future will take an infinite amount of time to compute. The future created by parfeval(@pause,0,Inf) is an extreme case of a future which can slow down a queue.

Cancel Futures Directly

You can use the State property to obtain the status of futures. Construct a cell array of the state of each future in f.

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

Every task except for the third pauses forever.

Cancel the second future directly with cancel.

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

After you cancel the second future, the third future runs. Wait until the third future completes, then examine the states again.

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

The third future now has the state 'finished'.

Check Completion Errors

When a future completes, its State property becomes 'finished'. To distinguish between futures which are cancelled and complete normally, use the Error property.

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): 

The code cancels the second future, as the message property indicates. The second future was cancelled, as stated in the message property. The third future completes without error, and therefore does not have an error message.

Cancel Futures in Pool Queue

You can use the FevalQueue property to access the futures in the pool queue.

p.FevalQueue
ans = 
 FevalQueue with properties: 

        Number Queued: 1
       Number Running: 2

The queue has two properties: RunningFutures and QueuedFutures. The RunningFutures property is an array of futures corresponding to tasks that are currently running.

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

The QueuedFutures property is an array of futures corresponding to tasks that are currently queued and not running.

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

You can cancel a single future or an array of futures. Cancel all the futures in QueuedFutures.

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

RunningFutures and QueuedFutures are sorted from newest to oldest, regardless of whether f is in order from newest to oldest. Each future has a unique ID property for the lifetime of the client. Check the ID property of each of the futures in 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

Compare the result against the ID property of each of the 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

Here, RunningFutures is an array containing f(1) and f(4). If you cancel RunningFutures(2), you cancel the fourth future f(4).

Sometimes, futures are not available in the workspace, for example, if you execute the same piece of code twice before it finishes, or if you use parfeval in a function. You can cancel futures that are not available in the workspace.

Clear f from the workspace.

clear f

You can use RunningFutures and QueuedFutures to access futures that have not yet completed. Use RunningFutures to cancel f(4).

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

To cancel all the futures still in the queue, use the following code.

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