我想启动一个共享的matlab会话,然后在同一个python 3脚本中立即连接到它。我还想在脚本完成后保持matlab会话的打开。因为将来,我想写一个类来做这件事,我想导入头中的所有库。
问题是,如果我导入以下库,python 3 脚本一直无法完成 os.system
或 subprocess.run
先用 matlab.engine
来连接到matlab。如下面的代码所示,我的脚本将永远被卡住。
# the following code cannot finish running
import os
import matlab.engine
os.system("matlab -r \"matlab.engine.shareEngine\"")
奇怪的是,如果我启动matlab,使用以下两种方法 os.system
或 subprocess.run
无需导入 matlab.engine
应验 前一个问题 建议,我可以顺利启动它。
我还注意到,如果我导入 matlab.engine
启动matlab后(示例代码如下),脚本将完成。然而这将使我的类非常丑陋......
# 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完成初始化之前,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脚本结束时,我们的MATLAB会话仍将开放,供将来使用。
对于第一种情况,这很容易。我们可以简单地用 matlab.engine.find_matlab()
.
对于第二种情况,棘手的部分是我们不能使用 matlab.engine.start_matlab
函数,因为正如我在 上一个答案,MATLAB进程的寿命与Python进程的寿命是绑定的。为了避免这种情况,我们希望使用 Python 库启动 MATLAB,例如使用 os
或 subprocess
.
然后要连接到新运行的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!