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

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 进程的方法的框架可能会像这样工作:

  1. 使用系统调用,从您的 MATLAB 会话启动一个或多个新的 MATLAB 进程,运行使用您想要的代码。
  2. 使用文件系统或内存映射文件在 MATLAB 进程之间传递函数输入、循环进度、输出、进程 ID 和超时时间。
  3. 使用原始 MATLAB 进程检查是否未达到超时时间,如果超时则终止有问题的进程并实例化一个新进程。
  4. 使用原始 MATLAB 进程收集函数输出(来自文件系统或内存映射文件)并退出。当没有更多工作剩余时,工人应该终止

我提供一个草图只是因为这个方法的完整工作实现相当复杂,事实上它已经实现并且在 batch_job toolbox 中公开可用。在 OP 的情况下,使用此工具箱(超时 10 秒)您将调用:

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

请注意,要使工具箱正常工作,其根目录需要在启动时位于您的 MATLAB 路径中。