簡體   English   中英

如何在指定的秒數后中斷 MATLAB 系統調用

[英]How to break a MATLAB system call after a specified number of seconds

我正在使用 Windows MATLAB 來運行 SSH 命令,但每隔一段時間 SSH 命令就會無限期掛起,然后我的 MATLAB 腳本也會掛起(有時會在一夜之間運行)。 在一定的等待時間后如何讓命令超時? 例如,假設我不想在 SSH 命令完成執行之前等待超過 3 秒,然后再中斷它並繼續:

% placeholder for a command that sometimes hangs
[status,result] = system('ssh some-user@0.1.2.3 sleep 10')
% placeholder for something I still want to run if the above command hangs
[status,result] = system('ssh some-user@0.1.2.3 ls') 

我想制作一個 function sys_with_timeout可以像這樣使用:

timeoutDuration = 3;
[status,result] = sys_with_timeout('ssh some-user@0.1.2.3 sleep 10', timeoutDuration)
[status,result] = sys_with_timeout('ssh some-user@0.1.2.3 ls', timeoutDuration) 

我已經嘗試過FEX 的超時 function,但它似乎不適用於系統/SSH 命令。

我認為system命令不是很靈活,而且我看不出有什么方法可以用它來做你想做的事。 但是我們可以為此使用 Java 內置的功能 MATLAB,根據André Caron 的回答

這是您等待進程超時完成的方式:

runtime = java.lang.Runtime.getRuntime();
process = runtime.exec('sleep 20');
process.waitFor(10, java.util.concurrent.TimeUnit.SECONDS);
if process.isAlive()
    disp("Done waiting for this...")
    process.destroyForcibly();
end
process.exitValue()

在示例中,我們運行sleep 20 shell 命令,然后waitFor()等待程序完成,但最多等待 10 秒。 我們輪詢以查看該進程是否仍在運行,如果是,則將其殺死。 如果需要, exitValue()會返回狀態。

運行sleep 5我看到:

ans =
     0

運行sleep 20我看到:

Done waiting for this...
ans =
   137

基於@Cris Luengo 的回答,這里是sys_with_timeout() function。我沒有使用process.waitFor() function,因為我寧願在 while 循環中等待並在它進入時顯示 output。while 循環中斷一次命令完成或超時,以先到者為准。

function [status,cmdout] = sys_with_timeout(command,timeoutSeconds,streamOutput,errorOnTimeout)
    arguments
        command char
        timeoutSeconds {mustBeNonnegative} = Inf
        streamOutput logical = true    % display output as it comes in
        errorOnTimeout logical = false % if false, display warning only
    end
    % launch command as java process (does not wait for output)
    process = java.lang.Runtime.getRuntime().exec(command);
    % start the timeout timer!
    timeoutTimer = tic();
    % Output reader (from https://www.mathworks.com/matlabcentral/answers/257278)
    outputReader = java.io.BufferedReader(java.io.InputStreamReader(process.getInputStream()));
    errorReader = java.io.BufferedReader(java.io.InputStreamReader(process.getErrorStream()));

    % initialize output char array
    cmdout = '';
    while true
        % If any lines are ready to read, append them to output
        % and display them if streamOutput is true
        if outputReader.ready() || errorReader.ready()
            if outputReader.ready()
                nextLine = char(outputReader.readLine());
            elseif errorReader.ready()
                nextLine = char(errorReader.readLine());
            end
            cmdout = [cmdout,nextLine,newline()];
            if streamOutput == true
                disp(nextLine);
            end
            continue
        else
            % if there are no lines ready in the reader, and the
            % process is no longer running, then we are done
            if ~process.isAlive()
                break
            end
            % Check for timeout.  If timeout is reached, destroy
            % the process and break
            if toc(timeoutTimer) > timeoutSeconds
                timeoutMessage = ['sys_with_timeout(''',command, ''',', num2str(timeoutSeconds), ')',...
                                  ' failed after timeout of ',num2str(toc(timeoutTimer)),' seconds'];
                if errorOnTimeout == true
                    error(timeoutMessage)
                else
                    warning(timeoutMessage)
                end
                process.destroyForcibly();
                break
            end
        end
    end
    if ~isempty(cmdout)
        cmdout(end) = []; % remove trailing newline of command output
    end
    status = process.exitValue(); % return
end

為簡單起見,將ssh some-user@0.1.2.3替換為wsl (當然需要WSL ),這是一個 function 超時的示例:

>> [status,cmdout] = sys_with_timeout('wsl echo start! && sleep 2 && echo finished!',1)
start!
Warning: sys_with_timeout('wsl echo start! && sleep 2 && echo finished!',1) failed after timeout of 1.0002 seconds 
> In sys_with_timeout (line 41) 
status =
     1
cmdout =
    'start!'

這是一個 function 沒有超時的例子:

>> [status,cmdout] = sys_with_timeout('wsl echo start! && sleep 2 && echo finished!',3)
start!
finished!
status =
     0
cmdout =
    'start!
     finished!'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM