Make a function time out in a parfor loop

17 ビュー (過去 30 日間)
Julia
Julia 2025 年 7 月 29 日
回答済み: Mike Croucher 2025 年 7 月 30 日
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 件のコメント
Walter Roberson
Walter Roberson 2025 年 7 月 29 日
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...

サインインしてコメントする。

回答 (1 件)

Mike Croucher
Mike Croucher 2025 年 7 月 30 日
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

カテゴリ

Help Center および File ExchangeLoops and Conditional Statements についてさらに検索

製品


リリース

R2023b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by