Make a function time out in a parfor loop
    11 vues (au cours des 30 derniers jours)
  
       Afficher commentaires plus anciens
    
This is not a question but rather an answer as I found no information on this topic anywhere but it took some time work out how to do it and I thought other people might have the same problem.
Essentially, I want to execute some code within a parfor loop but want to allow a maximum amount of time to do this. If the code hasn't finished running by then, I want to skip that iteration of the parfor loop. This proved a bit more tricky when done inside a parfor loop. The following code works for me under R2023b.
It is essential that you call parfeval with 'backgroundPool' in this case (else it runs it serial) and the desired behaviour is lost!
timeout = 5;
parfor a = 1:10
    tic
    F = parfeval(backgroundPool,@testfunction,3,a,b);
    while 1
        if toc > timeout && ~isequal(F.State, "finished")
            fprintf('Interrupted after %0.2f seconds\n', toc)
            cancel(F)
            break
        elseif isequal(F.State, "finished")
            fprintf("Finished in time - %0.2f seconds\n", toc)
            break
        end
    end
end
where testfunction is the following function with a random pause of maximum 10 seconds:
function [c, d, e] = testfunction(a, b)
c = a+b;
d = a-b;
e = a*b;
duration = rand(1)*10;      % Set a random pause time of between 0 and 10 seconds
pause(duration);
end
1 commentaire
  Walter Roberson
      
      
 le 29 Juil 2025
				Note that in order for this to work, the regular parfor has to be the process pool while the parfeval is the background pool. 
If the regular parfor is in the background pool, then there is the possibility that all of the available background pools are in use and so there would be no slots available to run the parfeval(), so it would remain queued until canceled.
... Though it is not really clear from the documentation whether a background pool thread is able to call parfeval...
Réponses (1)
  Mike Croucher
    
 le 30 Juil 2025
        You say you want to do this in a parfor-loop but is the use of parfor really a hard constraint?
I interpret your problem statement as 'I want to run a function many times in parallel and I want any individual instance to timeout after N seconds'. 
The way I'd do this is with a for-loop combined with parfeval.  This is what I've come up with.  I've deliberately made it verbose to help us see what is happening.  
timeout = 5;
b = 10;
numIterations = 10;
fprintf("Creating an array of futures and submitting them to the pool\n")
futures(1:numIterations) = parallel.FevalFuture;
tic
for a = 1:numIterations
    futures(a) = parfeval(@testfunction,3,a,b);
end
toc
fprintf("Submission completed\n")
numCancelled = 0;
while ~all(strcmp({futures.State}, 'finished')) % loop until all futures are finished
    pause(1); % Do this check once a second
    % get currently running futures
    runningFutures = futures(strcmp({futures.State}, 'running'));
    % Check if any currently running futures exceed the timeout
    for i = 1:numel(runningFutures)
        if seconds(runningFutures(i).RunningDuration) > timeout
            fprintf("Future %d exceeded timeout of %d seconds\n", runningFutures(i).ID, timeout);
            cancel(runningFutures(i));  % Cancel the future if it exceeds the timeout
            numCancelled = numCancelled + 1;
        end
    end
end
fprintf("All futures have been run\n")
fprintf("%d Futures were cancelled\n",numCancelled);
fprintf("Here is the Futures array. Cancelled ones are labelled wih 'Error'\n")
futures
fprintf("Here are just the sucessful ones. i.e. those that completed before the timeout")
successfulResults = futures(strcmp({futures.State}, 'finished') & cellfun(@isempty, {futures.Error}))
fprintf("And here at the outputs of the successful runs\n")
[res1,res2,res3] = fetchOutputs(successfulResults)
function [c, d, e] = testfunction(a, b)
c = a+b;
d = a-b;
e = a*b;
duration = rand(1)*10;      % Set a random pause time of between 0 and 100 seconds
pause(duration);
end
I ran this on my machine using parpool("Threads") and got the following output
Creating an array of futures and submitting them to the pool
Elapsed time is 0.026437 seconds.
Submission completed
Future 191 exceeded timeout of 5 seconds
Future 192 exceeded timeout of 5 seconds
Future 193 exceeded timeout of 5 seconds
Future 194 exceeded timeout of 5 seconds
Future 195 exceeded timeout of 5 seconds
Future 196 exceeded timeout of 5 seconds
Future 197 exceeded timeout of 5 seconds
All futures have been run
7 Futures were cancelled
Here is the Futures array. Cancelled ones are labelled wih 'Error'
futures = 
 1x10 FevalFuture array:
         ID              State        FinishDateTime       Function  Error
       -------------------------------------------------------------------
    1   190  finished (unread)  30-Jul-2025 13:37:15  @testfunction       
    2   191  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    3   192  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    4   193  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    5   194  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    6   195  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    7   196  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    8   197  finished (unread)  30-Jul-2025 13:37:18  @testfunction  Error
    9   198  finished (unread)  30-Jul-2025 13:37:15  @testfunction       
   10   199  finished (unread)  30-Jul-2025 13:37:15  @testfunction       
Here are just the sucessful ones. i.e. those that completed before the timeout
successfulResults = 
 1x3 FevalFuture array:
         ID              State        FinishDateTime       Function  Error
       -------------------------------------------------------------------
    1   190  finished (unread)  30-Jul-2025 13:37:15  @testfunction       
    2   198  finished (unread)  30-Jul-2025 13:37:15  @testfunction       
    3   199  finished (unread)  30-Jul-2025 13:37:15  @testfunction       
And here at the outputs of the successful runs
res1 =
    11
    19
    20
res2 =
    -9
    -1
     0
res3 =
    10
    90
   100
0 commentaires
Voir également
Catégories
				En savoir plus sur Loops and Conditional Statements dans Help Center et File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


