不能在头文件中同时导入os.system和matlab.engine。

问题描述 投票:0回答:1

我想启动一个共享的matlab会话,然后在同一个python 3脚本中立即连接到它。我还想在脚本完成后保持matlab会话的打开。因为将来,我想写一个类来做这件事,我想导入头中的所有库。

问题是,如果我导入以下库,python 3 脚本一直无法完成 os.systemsubprocess.run 先用 matlab.engine 来连接到matlab。如下面的代码所示,我的脚本将永远被卡住。

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

截图。Screenshot of not working code

奇怪的是,如果我启动matlab,使用以下两种方法 os.systemsubprocess.run 无需导入 matlab.engine 应验 前一个问题 建议,我可以顺利启动它。

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

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

截图。Screenshot of working code

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

是什么原因导致脚本无法完成的问题?如何在头文件中同时导入 ossubprocess 和 matlab.engine?我必须让脚本停止运行一段时间以等待matlab完成初始化吗?

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

python python-3.x matlab subprocess matlab-engine
1个回答
2
投票

这里有一个解决方案。

  • 连接到一个现有的会话,如果有的话
  • 创建一个新的会话并连接到它,如果没有的话。

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


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

  • 对于第二种情况,棘手的部分是我们不能使用 matlab.engine.start_matlab 函数,因为正如我在 上一个答案,MATLAB进程的寿命与Python进程的寿命是绑定的。为了避免这种情况,我们希望使用 Python 库启动 MATLAB,例如使用 ossubprocess.

    然后要连接到新运行的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!
© www.soinside.com 2019 - 2024. All rights reserved.