在给定时间后突破专有工具箱
Break out of proprietary toolbox after a given time
我在 MATLAB 中迭代一个大型测试矩阵,每次都调用第二方专有软件(运行 在 MATLAB 中)。我无法编辑软件源代码。有时,软件挂了,所以我想在一定时间后退出并继续下一次迭代。
在伪代码中,我这样做:
for i = 1:n
output(i) = proprietary_software(input(i));
end
如果专有软件耗时过长,我如何才能跳到下一个迭代(并可能保存 output(i)='too_long'
)?
您需要从另一个 Matlab 实例调用 Matlab。 Matlab 的另一个实例将 运行 命令并将控制权释放给 Matlab 的第一个实例,等待它保存结果或达到特定时间。在这种情况下,它将等待 30 秒。
您将需要 1 个附加功能。确保这个函数在 Matlab 路径上。
function proprietary_software_caller(input)
hTic=tic;
output=proprietary_software(input);
hToc=toc(hTic);
if hToc<30
save('outfile.mat','output');
end
exit;
end
您将需要以这种方式修改您的原始脚本
[status,firstPID] = str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do @echo %~F'')'));
for i = 1:n
inputStr=num2str(input(i));
system(['matlab.exe -nodesktop -r proprietary_software_caller\(',inputStr,'\)&']);
hTic=tic;
hToc=toc(hTic);
while hToc<30 || ~(exist('outfile.mat','file')==2)
hToc=toc(hTic);
end
if hToc>=30
output(i)= 'too_long';
[status,allPIDs]=str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do @echo %~F'')'));
allPIDs(allPIDs==firstPID)=[];
for a=1:numel(allPIDs)
[status,cmdout]=system(['taskkill /F /pid ' sprintf('%i',allPIDs(a))]);
end
elseif exist('outfile.mat','file')==2
loadedData=load('outfile.mat');
output(i)=loadedData.output;
delete('outfile.mat');
end
end
希望对您有所帮助。
您实质上是在寻求一种在 MATLAB 代码上实现超时的方法。这可能非常难以实施。首先要说明的是,如果有问题的 MATLAB 代码无法通过干净退出或抛出错误来终止自身,那么 not 可能在不退出或终止代码的情况下终止代码有问题的 MATLAB 过程。例如,在外部创建的计时器中抛出错误是行不通的;错误被捕获。
因此要问的第一个问题是:
Can the over-running code be made to terminate itself?
这取决于过度运行的原因,以及您对源代码的访问:
- 如果程序陷入无限(或非常长-运行ning)循环,无论是在 MATLAB 代码中还是在您拥有源代码的 mex 文件中,或者调用用户定义的回调每次迭代,然后你可以让这段代码自行终止。
- 如果程序卡在您没有源代码的 MATLAB 内置函数、p 代码文件或 mex 文件中,并且不支持定期调用回调,那么它会成功你有可能让代码自行终止。
让我们来解决第一个案例。让代码自行终止的最简单方法是让它抛出一个错误,如果超过超时时间,调用者会捕获该错误。例如。在 OP 的情况下:
for i = 1:n
tic();
try
output(i) = proprietary_software(input(i));
catch
end
end
在 over-运行ning 循环的某处使用以下代码,或在循环回调或 mex 文件中调用:
assert(toc() < 10, 'Timed out');
现在来看第二种情况。您需要终止此 MATLAB 进程,因此将其作为您从当前 MATLAB 会话中生成的 MATLAB 进程是有意义的。您可以使用类似于此的系统调用来执行此操作:
system('matlab -nodisplay -r code_to_run()')
虽然 MATLAB 进程在某些情况下可能会自行退出,这在这里可能会用到(例如调用 quit('force')
的计时器函数),但终止 MATLAB 进程的最可靠方法是执行通过系统调用,使用 taskkill
(Windows) 或 kill
(Linux/Mac).
使用生成和终止超时 MATLAB 进程的方法的框架可能会像这样工作:
- 使用系统调用,从您的 MATLAB 会话启动一个或多个新的 MATLAB 进程,运行使用您想要的代码。
- 使用文件系统或内存映射文件在 MATLAB 进程之间传递函数输入、循环进度、输出、进程 ID 和超时时间。
- 使用原始 MATLAB 进程检查是否未达到超时时间,如果超时则终止有问题的进程并实例化一个新进程。
- 使用原始 MATLAB 进程收集函数输出(来自文件系统或内存映射文件)并退出。当没有更多工作剩余时,工人应该终止
我提供一个草图只是因为这个方法的完整工作实现相当复杂,事实上它已经实现并且在 batch_job toolbox 中公开可用。在 OP 的情况下,使用此工具箱(超时 10 秒)您将调用:
output = batch_job(@proprietary_software, input(:)', '-timeout', 10);
请注意,要使工具箱正常工作,其根目录需要在启动时位于您的 MATLAB 路径中。
我在 MATLAB 中迭代一个大型测试矩阵,每次都调用第二方专有软件(运行 在 MATLAB 中)。我无法编辑软件源代码。有时,软件挂了,所以我想在一定时间后退出并继续下一次迭代。
在伪代码中,我这样做:
for i = 1:n
output(i) = proprietary_software(input(i));
end
如果专有软件耗时过长,我如何才能跳到下一个迭代(并可能保存 output(i)='too_long'
)?
您需要从另一个 Matlab 实例调用 Matlab。 Matlab 的另一个实例将 运行 命令并将控制权释放给 Matlab 的第一个实例,等待它保存结果或达到特定时间。在这种情况下,它将等待 30 秒。
您将需要 1 个附加功能。确保这个函数在 Matlab 路径上。
function proprietary_software_caller(input)
hTic=tic;
output=proprietary_software(input);
hToc=toc(hTic);
if hToc<30
save('outfile.mat','output');
end
exit;
end
您将需要以这种方式修改您的原始脚本
[status,firstPID] = str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do @echo %~F'')'));
for i = 1:n
inputStr=num2str(input(i));
system(['matlab.exe -nodesktop -r proprietary_software_caller\(',inputStr,'\)&']);
hTic=tic;
hToc=toc(hTic);
while hToc<30 || ~(exist('outfile.mat','file')==2)
hToc=toc(hTic);
end
if hToc>=30
output(i)= 'too_long';
[status,allPIDs]=str2double(system('for /f "tokens=2 delims=," %F in (''tasklist /nh /fi "imagename eq Matlab.exe" /fo csv) do @echo %~F'')'));
allPIDs(allPIDs==firstPID)=[];
for a=1:numel(allPIDs)
[status,cmdout]=system(['taskkill /F /pid ' sprintf('%i',allPIDs(a))]);
end
elseif exist('outfile.mat','file')==2
loadedData=load('outfile.mat');
output(i)=loadedData.output;
delete('outfile.mat');
end
end
希望对您有所帮助。
您实质上是在寻求一种在 MATLAB 代码上实现超时的方法。这可能非常难以实施。首先要说明的是,如果有问题的 MATLAB 代码无法通过干净退出或抛出错误来终止自身,那么 not 可能在不退出或终止代码的情况下终止代码有问题的 MATLAB 过程。例如,在外部创建的计时器中抛出错误是行不通的;错误被捕获。
因此要问的第一个问题是:
Can the over-running code be made to terminate itself?
这取决于过度运行的原因,以及您对源代码的访问:
- 如果程序陷入无限(或非常长-运行ning)循环,无论是在 MATLAB 代码中还是在您拥有源代码的 mex 文件中,或者调用用户定义的回调每次迭代,然后你可以让这段代码自行终止。
- 如果程序卡在您没有源代码的 MATLAB 内置函数、p 代码文件或 mex 文件中,并且不支持定期调用回调,那么它会成功你有可能让代码自行终止。
让我们来解决第一个案例。让代码自行终止的最简单方法是让它抛出一个错误,如果超过超时时间,调用者会捕获该错误。例如。在 OP 的情况下:
for i = 1:n
tic();
try
output(i) = proprietary_software(input(i));
catch
end
end
在 over-运行ning 循环的某处使用以下代码,或在循环回调或 mex 文件中调用:
assert(toc() < 10, 'Timed out');
现在来看第二种情况。您需要终止此 MATLAB 进程,因此将其作为您从当前 MATLAB 会话中生成的 MATLAB 进程是有意义的。您可以使用类似于此的系统调用来执行此操作:
system('matlab -nodisplay -r code_to_run()')
虽然 MATLAB 进程在某些情况下可能会自行退出,这在这里可能会用到(例如调用 quit('force')
的计时器函数),但终止 MATLAB 进程的最可靠方法是执行通过系统调用,使用 taskkill
(Windows) 或 kill
(Linux/Mac).
使用生成和终止超时 MATLAB 进程的方法的框架可能会像这样工作:
- 使用系统调用,从您的 MATLAB 会话启动一个或多个新的 MATLAB 进程,运行使用您想要的代码。
- 使用文件系统或内存映射文件在 MATLAB 进程之间传递函数输入、循环进度、输出、进程 ID 和超时时间。
- 使用原始 MATLAB 进程检查是否未达到超时时间,如果超时则终止有问题的进程并实例化一个新进程。
- 使用原始 MATLAB 进程收集函数输出(来自文件系统或内存映射文件)并退出。当没有更多工作剩余时,工人应该终止
我提供一个草图只是因为这个方法的完整工作实现相当复杂,事实上它已经实现并且在 batch_job toolbox 中公开可用。在 OP 的情况下,使用此工具箱(超时 10 秒)您将调用:
output = batch_job(@proprietary_software, input(:)', '-timeout', 10);
请注意,要使工具箱正常工作,其根目录需要在启动时位于您的 MATLAB 路径中。