Выйти из запатентованной панели инструментов через определенное время

Я повторяю большую тестовую матрицу в MATLAB и каждый раз вызываю стороннее проприетарное программное обеспечение (работает в MATLAB). Я не могу редактировать исходный код программного обеспечения. Иногда программное обеспечение зависает, поэтому я хочу выйти из него через определенное время и перейти к следующей итерации.

В псевдокоде я делаю это:

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

Как я могу перейти к следующей итерации (и, возможно, сохранить output(i)='too_long'), если проприетарное программное обеспечение занимает слишком много времени?

Ответ 1

Вам нужно будет вызвать Matlab из другого экземпляра Matlab. Другой экземпляр Matlab будет запускать команду и управлять выпуском в первый экземпляр Matlab, чтобы ждать, пока он либо сохраняет результаты, либо достигает определенного времени. В этом случае он будет ждать 30 секунд.

Вам понадобится еще одна функция. Убедитесь, что эта функция находится на пути 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

Вам нужно будет изменить свой оригинальный script таким образом

[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

Надеюсь, это поможет.

Ответ 2

В основном вы запрашиваете способ реализовать тайм-аут в коде 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, может работать следующим образом:

  • Используя системные вызовы, запустите один или несколько новых процессов MATLAB с вашего сеанса MATLAB, выполнив нужный вам код.
  • Используйте файловую систему или файл с отображением памяти для обмена данными между процессами MATLAB с входами функций, ходом цикла, выходами, идентификаторами процессов и временем ожидания.
  • Использовать исходный процесс MATLAB для проверки того, что время ожидания не достигнуто, или если это так, чтобы завершить процесс, о котором идет речь, и создать новый экземпляр.
  • Используйте исходный процесс MATLAB для сбора выходных данных функции (либо из файловой системы, либо из файла с отображением памяти) и выхода. Работники должны прекратить работу, когда осталось больше работы.

Я предоставляю эскиз только потому, что полная рабочая реализация этого подхода довольно привлекательна, и на самом деле он уже реализован и доступен для публики в batch_job набор инструментов. В случае OP, используя эту панель инструментов (с тайм-аутом 10 секунд), вы должны позвонить:

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

Обратите внимание, что для работы инструментария его корневой каталог должен находиться на вашем пути MATLAB при запуске.