在给定时间后打破专有工具箱

时间:2015-12-17 03:58:22

标签: matlab timeout break

我每次都在MATLAB中迭代一个大的测试矩阵并调用第二方专有软件(在MATLAB中运行)。我无法编辑软件源代码。有时候,软件会挂起,所以我想在一段时间后退出它并继续下一次迭代。

在伪代码中,我这样做:

for i = 1:n
    output(i) = proprietary_software(input(i));
end

如果专有软件耗时太长,我怎样才能跳到下一次迭代(并可能保存output(i)='too_long')?

2 个答案:

答案 0 :(得分:1)

您需要从另一个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

我希望这会有所帮助。

答案 1 :(得分:1)

您实际上是在寻求一种在MATLAB代码上实现超时的方法。实施起来可能会非常棘手。首先要说明的是,如果有问题的MATLAB代码无法自行终止,无论是通过干净地退出还是抛出错误,那么可以在不退出或终止MATLAB进程的情况下终止代码题。例如,在外部创建的计时器中抛出错误不起作用;错误被捕获。

首先要问的问题是:

  

是否可以使超限代码自行终止?

这取决于过度运行的原因,以及您对源代码的访问:

  • 如果程序陷入无限(或非常长时间)循环,无论是在MATLAB代码中还是在您拥有源代码的mex文件中,或者每次迭代都调用用户定义的回调,那么您可以获得这段代码终结了。
  • 如果程序卡在MATLAB内置程序,或者没有源代码的p代码文件或mex文件中,并且不支持定期调用回调,那么你不可能让代码终止自己。

让我们解决第一个案例。让代码终止自身的最简单方法是让它抛出一个错误,如果它超过了超时时间,它会被调用者捕获。例如。在OP的案例中:

for i = 1:n
    tic();
    try
        output(i) = proprietary_software(input(i));
    catch
    end
end

在溢出循环中的某处使用以下代码,或在循环回调或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流程的框架可能会这样:

  1. 使用系统调用,从MATLAB会话中启动一个或多个新的MATLAB进程,运行您想要的代码。
  2. 使用文件系统或内存映射文件在MATLAB处理函数输入,循环进度,输出,进程ID和超时时间之间进行通信。
  3. 使用原始MATLAB流程检查尚未达到的超时时间,或者如果是,则终止相关流程并实例化新流程。
  4. 使用原始MATLAB过程收集函数输出(来自文件系统或内存映射文件)并退出。当没有剩余工作时,工人应该终止
  5. 我之所以提供草图只是因为这种方法的完整工作实施得到了公平的参与,事实上它已经实施并在batch_job toolbox中公开提供。在OP的情况下,使用此工具箱(超时10秒),您可以致电:

    output = batch_job(@proprietary_software, input(:)', '-timeout', 10);
    

    请注意,要使工具箱正常工作,其根目录必须在启动时位于MATLAB路径上。