无法在 header 中同时导入 os.system 和 matlab.engine

Can't import os.system and matlab.engine at the same time in the header

我想启动一个共享的 matlab session 然后在同一个 python 3 脚本中立即连接到它。我还想在脚本完成后让我的 matlab session 保持打开状态。因为以后要写一个class来做这个,我想导入header.

里的所有库

问题是,如果我先导入 os.systemsubprocess.run,然后使用 matlab.engine 连接到 matlab,python 3 脚本总是无法完成。如下代码所示,我的脚本将永远stuck/hanged。

# the following code cannot finish running
import os
import matlab.engine
os.system("matlab -r \"matlab.engine.shareEngine\"")

截图:

奇怪的是,如果我使用 os.systemsubprocess.run 启动 matlab 而没有导入 matlab.engine 作为我 建议的答案,我可以在没有任何导入的情况下启动它问题。

我还注意到,如果我在启动 matlab(下面的示例代码)之后导入 matlab.engine,脚本将会完成。然而,这会使我的 class 变得非常丑陋...

# the following code can finish running
import os
os.system("matlab -r \"matlab.engine.shareEngine\"")
import matlab.engine

截图:

我试图通过使用 subprocess.Popen 绕过这个问题。它确实启动了 matlab 并尝试使用 matlab.engine 不间断地连接到它,但是脚本永远无法连接到 matlab 因为 matlab.engine 会在 matlab 完成初始化之前尝试连接。

导致脚本无法完成的问题的原因是什么?如何在 header 中同时导入 os/subprocess 和 matlab.engine?我是否必须让脚本停止 运行 一段时间才能等待 matlab 完成初始化?

For future people: os.system keeps open until called MATLAB exits. That's why the script can't close itself.

这是一个解决方案:

  • 连接到现有会话(如果有的话)
  • 创建一个新会话,如果没有则连接到它

当 Python 脚本结束时,我们的 MATLAB 会话仍将打开以供将来使用。


  • 对于第一种情况,这很简单。我们可以简单地使用 matlab.engine.find_matlab().

  • 检查现有会话
  • 对于第二种情况,棘手的部分是我们不能使用 matlab.engine.start_matlab 函数,因为正如我在 中提到的,MATLAB 进程的生命周期是固定的到 Python 过程。为避免这种情况,我们希望使用 Python 库启动 MATLAB,例如使用 ossubprocess.

    然后连接到新的 运行ning MATLAB,我们需要先从 MATLAB 共享引擎,然后从 Python 连接到它。但要做到这一点,我们需要 pid,我们不能直接得到它,因为 MATLAB 需要一些时间来启动。

    为了解决这个问题,在我的解决方案中,我使用了一个简单的文本文件,其中 MATLAB 在启动时立即将其转储为 pid。 当文件存在时,我们知道 MATLAB 已准备就绪,因此我们可以连接到它。


import subprocess
import matlab.engine
import time
import os

class Test:
    def __init__(self):
        existing_session = self._check_existing_matlab_sessions()
        if existing_session:
            print("Using existing MATLAB session")
            eng = matlab.engine.connect_matlab(existing_session)
            print(f"Connected to {existing_session}")

        else:
            print("Creating new MATLAB session.")
            eng, pid = self._open_new_matlab_session()
            print(f"Connected to MATLAB_{pid}!")

    def _check_existing_matlab_sessions(self):
        sessions = matlab.engine.find_matlab()
        if sessions:
            return sessions[0]
        return ()

    def _open_new_matlab_session(self):
        pid_log = os.path.join(os.getcwd(),'pid_logfile.txt')
        if os.path.exists(pid_log):
            os.remove(pid_log)

        process = subprocess.Popen([r"C:\Program Files\MATLAB\R2020a\bin\matlab.exe","-r","matlab.engine.shareEngine; fid=fopen(fullfile(pwd,'pid_logfile.txt'),'w'); pid=feature('getpid'); fprintf(fid,'%d',pid); fclose(fid)"])

        while not os.path.exists(pid_log):
            time.sleep(1)

        f = open(pid_log, "r")
        pid = f.read(5)

        try:
            eng1 = matlab.engine.connect_matlab(f'MATLAB_{pid}')
            return eng1, pid
        except:
            raise Exception("Could not connect to MATLAB")

if __name__ == "__main__":
    Test()

当您 运行 脚本时,如果存在现有会话,它将连接到它:

$ python main.py
Using existing MATLAB session
Connected to MATLAB_16480

如果没有,它将创建一个并连接到它:

$ python main.py
Creating new MATLAB session.
Connected to MATLAB_39372!