Make a function time out in a parfor loop
17 次查看(过去 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
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
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
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Loops and Conditional Statements 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!