在这种情况下如何关闭 MATLAB 会话?

How to close MATLAB session in this case?

我正在 运行 MATLAB 使用 Python 的 subprocess 像这样。 main.py如下:

process = subprocess.Popen("bash run.sh", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
stdout = process.communicate()[0]

run.sh是这样的:

export PATH=...
/usr/local/MATLAB/R2017b/bin/matlab -r "run('mainscript.m');exit;"

mainscript.m,主要的事情都在那里完成。

问题是,当 运行 宁 mainscript.m 时出现一些错误, process 似乎被卡住了。并且 MATLAB 进程不会正常退出。 似乎 MATLAB 会话仍然是 运行ning 没有退出,因此 main.py 仍然是 运行ning 没有退出,这似乎被卡住了。但实际上 main.py 需要退出或发出一些警报。

所以我的问题是,在 /usr/local/MATLAB/R2017b/bin/matlab -r "run('mainscript.m');exit; 中出现错误时,有什么方法可以退出 MATLAB 会话吗?

期待您的建议。谢谢。

更新:

在阅读了友好的评论和回答后,我提供了更多细节以澄清这个问题。

main.py是:

import subprocess
import time
from threading import Thread


def main(param1):
    process = subprocess.Popen('bash run.sh', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
    start = time.time()
    stdout = process.communicate()[0]
    elapsed = time.time() - start
    print('log: {}, {}, {}'.format(param1, stdout, elapsed))


if __name__=='__main__':
    _param = {"param1":"param1"}
    thread = Thread(target=main, kwargs=_param)
    thread.start()

run.sh是:

/usr/local/MATLAB/R2017b/bin/matlab -r "run('matlabscript.m');exit;"

matlabscript.m 是(xxxx 不是有效的 function/script,这会导致错误。):

xxxx;

当运行宁python main.py时,ps -u的输出是:

ubuntu    4901  0.0  0.0 218624  5392 pts/4    Sl+  08:10   0:00 python main.py
ubuntu    4903  0.0  0.0 113280  1192 pts/4    S+   08:10   0:00 bash run.sh
ubuntu    4904  9.0  3.1 5702484 512812 pts/4  Sl+  08:10   0:06 /usr/local/MATLAB/R2017b/bin/glnxa64/MATLAB -r run('matlabscript.m');exit; -prefersoftwareopengl
ubuntu    5025  0.0  0.0 115544  2004 pts/3    Ss   08:11   0:00 -bash
ubuntu    5044  0.0  0.0 155436  1852 pts/3    R+   08:11   0:00 ps -u

并且 python main.py 被卡住 并且不会正常退出。所以我kill 4901,然后ps -u,它显示:

ubuntu    4903  0.0  0.0 113280  1192 pts/4    S    08:10   0:00 bash run.sh
ubuntu    4904  4.7  3.1 5702484 512812 pts/4  Sl   08:10   0:06 /usr/local/MATLAB/R2017b/bin/glnxa64/MATLAB -r run('matlabscript.m');exit; -prefersoftwareopengl
ubuntu    5025  0.0  0.0 115544  2052 pts/3    Ss   08:11   0:00 -bash
ubuntu    5047  0.0  0.0 155436  1852 pts/3    R+   08:12   0:00 ps -u

这意味着 MATLAB 的子进程仍然 运行ning 没有退出。

但是,以下是可以的。 main_with_try_catch.py 是:

import subprocess
import time
from threading import Thread


def main(param1):
    process = subprocess.Popen('bash run_with_try_catch.sh', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
    start = time.time()
    stdout = process.communicate()[0]
    elapsed = time.time() - start
    print('log: {}, {}, {}'.format(param1, stdout, elapsed))


if __name__=='__main__':
    _param = {"param1":"param1"}
    thread = Thread(target=main, kwargs=_param)
    thread.start()

run_with_try_catch.sh是:

/usr/local/MATLAB/R2017b/bin/matlab -r "try,run('matlabscript.m'),catch,fprintf('error occured'),end;exit;"

然后,运行 python main_with_try_catch.py,显示:

[ubuntu@localhost ~]$ python main_with_try_catch.py
log: param1, MATLAB is selecting SOFTWARE OPENGL rendering.

                                                                              < M A T L A B (R) >
                                                                    Copyright 1984-2017 The MathWorks, Inc.
                                                                     R2017b (9.3.0.713579) 64-bit (glnxa64)
                                                                               September 14, 2017


To get started, type one of these: helpwin, helpdesk, or demo.
For product information, visit www.mathworks.com.

error occured, 7.47159695625
[ubuntu@localhost ~]$

表示MATLAB正常退出。并检查ps -u,没有剩余进程。

运行 线程中的 subprocess,如果没有正常退出,则在给定的超时后终止它。在此处查找示例:

要关闭进程,您可以在子进程中使用普通的 killkill -TERM $(pgrep -f matlab)

或使用方法:

    import os
    import signal
    def find_process_and_close(process_name):
        output = subprocess.getoutput("ps -A -o pid= -o cmd=")
        for line in output.splitlines():
            if process_name in line:
                pid = int(line.split()[0])
                os.kill(pid, signal.SIGTERM)
                print("Terminate process {}".format(line))
                return True
        return False

psutil 包的另一种方法:

    import psutil
    def find_process_and_close_with_psutil(process_name):
        for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
            if proc.info['cmdline'] and process_name in proc.info['cmdline']:
                print("Terminate process {}".format(proc.info))
                proc.kill()
                return True
        return False

编辑 看完评论。 您可以连续读取脚本的输出,如果发现有趣的字符串,例如'error' 消息,只需终止 运行 进程(包括所有子进程):

    proc = subprocess.Popen(["bash run.sh"],
                            preexec_fn=os.setsid, # to kill all spawned processes
                            stdout=subprocess.PIPE,
                            stderr=subprocess.STDOUT)
    pid_to_terminate = None
    try:
        for stdout_line in iter(proc.stdout.readline, ''):
            line = stdout_line.decode().strip()
            print(line)
            #look for 'error' in the output
            if "error" in line:
                print("ERROR found in script output")
                pid_to_terminate = proc.pid
                break
    finally:
        proc.stdout.close()
    
    if pid_to_terminate:
        # kill with all spawned processes
        os.killpg(os.getpgid(pid_to_terminate), signal.SIGTERM)

不要在 MATLAB 启动时使用 -r 到 运行 脚本。请改用 -batch 选项。

-r 选项表示“启动 MATLAB 和 运行 这个脚本,完成后留在命令提示符下”。该脚本旨在初始化环境。这就是为什么你的脚本需要以 exit 结尾,如果你想 运行 它是非交互的,就不会出错。

-batch 选项表示“运行 这个脚本然后以 success/failure 状态退出 MATLAB”。它旨在以非交互方式执行用 MATLAB 语言编写的脚本。它不显示初始屏幕,也不加载 GUI,而是通过 stdout 和 stderr 产生输出。参见 the docs。此选项从 R2019a 开始存在。