MATLAB interrupting the algorithm by timer

조회 수: 11 (최근 30일)
Alexander Voznesensky
Alexander Voznesensky 2020년 12월 14일
편집: Brian Harris 2023년 4월 6일
Hi! I need to set a time limit on an algorithm. I want to throw an error and stop while cycle in try block after 3 seconds, then I want to handle the error in catch block. MATLAB gives me the following diagnostics: Error while evaluating TimerFcn for timer 'timer-2'. Text message 'Error!' is displayed, but error isn't thrown and while cycle is still running. Text message 'Error is caught!' isn't displayed. Could you help me?
t = timer;
t.StartDelay = 3;
t.TimerFcn = @(myTimerObj, thisEvent)error('Error!');
start(t)
a=0;
try
while(1)
if a==1
break;
end
end
stop(t);
delete(t);
catch
stop(t);
delete(t);
disp('Error is caught!')
end

답변 (3개)

Jan
Jan 2020년 12월 18일
편집: Jan 2020년 12월 18일
The timer runs in its own thread. The execution of the timer callback is correctly stopped by the error command, but not the regular processing of other Matlab functions.
Which function to you want to interrupt? If it is e.g. an ODE integrator, you can check the value of a flag in the event function:
[value,isterminal,direction] = myEventsFcn(t,y)
position = y(1); % The value that we want to be zero
isterminal = 0; % Halt integration
direction = 0;
Terminator = getappdata(groot, 'TheTerminator');
if Terminator
isterminal = 1;
end
Now you can set this flag by setappdata(groot, 'TheTerminator') from your TIMER callback.
Many builtin functions allow such requests during the processing, but some doesn't. E.g. a huge linear algebra computation cannot be triggered by this method. Then for longer operations it can be an option to start a 2nd instance of Matlab and kill it after a certain time. For a 3 sec limit this will be inefficient, because starting Matlab takes longer already. But for some minutes this would work.
Which operating system are you using?
runtime = java.lang.Runtime.getRuntime();
process = runtime.exec('matlab -nodisplay -nosplash -nodesktop -r "YourFunction; exit"');
pause(100); % Or do what you want
try
exitCode = process.exitValue();
disp('Process has finished.');
catch ME
% Still running...
process.destroy(); % Sorry, I give up
end
  댓글 수: 4
Brian Harris
Brian Harris 2023년 4월 6일
This seems to spawn a process faster than trying to start a parpool; and has fewer (different? restirctions... can spawn plots for e.g.)
Brian Harris
Brian Harris 2023년 4월 6일
OK, follow-up question. If I'm using a parfeval I can get the output stream from the subprocess via
f = parfeval(@()disp('hi'), 0)
f.Diary
% ans =
% 'hi
% '
But, how do I do this with "process"? Digging in a bit, it looks like we can get the input stream (what the subprocess puts out...) via:
in_strm = process.getInputStream();
But getting the same kind of "diary" data is a bit involved... and doesn't seem to be working. I pieced together this from another answer from Benjamin Davis:
runtime = java.lang.Runtime.getRuntime();
process = runtime.exec('matlab -nodesktop -nosplash -nodesktop -r "foo; exit"');
% pause(30); % Or do what you want
in_strm = process.getInputStream();
% out_strm = process.getOutputStream();
getMethod_args = javaArray('java.lang.Class',3);
byteArrayName = '[B';
getMethod_args(1) = java.lang.Class.forName(byteArrayName);
getMethod_args(2) = java.lang.Integer.TYPE;
getMethod_args(3) = java.lang.Integer.TYPE;
m_read = in_strm.getClass().getMethod('read',getMethod_args);
read_args = java.util.ArrayList();
% num_available = in_strm.available();
% buf_size = max(1024, num_available);
buf_size = 1024;
buf_ptr = 0;
while process.isAlive()
read_args.add(zeros(1, buf_size, 'int8'));
read_args.add(int32(buf_ptr));
read_args.add(int32(buf_size));
disp('this seems to block...');
n_read = m_read.invoke(in_strm, read_args.toArray());
disp('... this does not print until after the process is killed');
out = char(read_args.get(0));
out = out(:)';
out = out(1:n_read);
disp(out);
buf_ptr = n_read;
fprintf('alive... %s\n', datetime)
pause(1);
end
try
exitCode = process.exitValue();
disp('Process has finished.');
catch ME
% Still running...
process.destroy(); % Sorry, I give up
end
But It the "avaliable" flag is always 0, so I get nothing out... am I barking up the wrong stream?
For completeness, foo.m:
function foo()
for i = 1:10
disp(i);
pause(1);
end
disp('Done');
end

댓글을 달려면 로그인하십시오.


Joseph Wilson
Joseph Wilson 2020년 12월 14일
편집: Walter Roberson 2023년 4월 6일
clear;clc
timerval = tic;
while 1
endval = toc(timerval);
if endval>=3
break
end
end
%tic/toc are built in matlab functions to count time. This utilizes them to count seconds for length of time running through the loop
  댓글 수: 5
Joseph Wilson
Joseph Wilson 2020년 12월 15일
Are those slow functions written by you or are they built in matlab functions that your can't change? If they are written by you, you can add in time checking sections inside those functions to break out of the function if it has taken too long. If they are not able to be editted by you, you might be out of luck with this method.
This is a similar problem if you cannot edit the functions.
I do not think timer has the ability to end a function like you want it to.
Alexander Voznesensky
Alexander Voznesensky 2020년 12월 16일
Yes, they are built in matlab functions...

댓글을 달려면 로그인하십시오.


Brian Harris
Brian Harris 2023년 4월 6일
편집: Brian Harris 2023년 4월 6일
If you are ok with the limitations of a parfeval call (need parallel processing toolbox, any graphics produced by the calling function are surpressed, ...) you can easily cancel the call without spawning a new matlab instance.
localPool = gcp('nocreate');
if isempty(localPool)
% the parpool is a singlton, so if its not running, start it.
localPool = parpool("local", 2, 'IdleTimeout', 24 * 60);
end
% To get outputs call "fetchOutputs(f)", but this blocks the main thread, so
% instead you can montor f.Result in a killable loop, timer or listener...
f = parfeval(localPool, @pause, 0, Inf);
% for now we'll just kill the execution after 3 seconds
death_clock = timer( ...
'ExecutionMode', 'singleShot', ...
'StartDelay', 3.0, ...
'TimerFcn', @(~, ~)cancel(f) ...
);
% Show the FevalFuture object
disp(f);
fprintf('Started death clock at: %s\n', datetime);
death_clock.start(); % start the death clock
% Monitor for completion/termination
while ~strcmp(f.State, 'finished')
fprintf('waiting to finish... %s\n', datetime);
pause(1);
end
fprintf('Finished... %s\n', datetime);
disp(f);
  댓글 수: 4
Walter Roberson
Walter Roberson 2023년 4월 6일
You might also be interested in experimenting with the newer backgroundPool and parfeval -- which can be canceled as well. background pools should normally be faster than parpool but have some restrictions on what they can do.
Brian Harris
Brian Harris 2023년 4월 6일
편집: Brian Harris 2023년 4월 6일
Thanks Walter. I'll have to give that a shot. Sadly my current project is stuck with R2020a (backgroundPool was introduced in R2021b); will try that out on the next project! Note, using parpool('threads') is supposedly similar, so I'll give that a try; though there are some additonal limitations over the local.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Parallel Computing Fundamentals에 대해 자세히 알아보기

제품

Community Treasure Hunt

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

Start Hunting!

Translated by