0

I want to start a shared matlab session then connect to it right away in the same python 3 script. I also want to keep my matlab session opened after the script finishes. Because in the future, I want to write a class to do this, I would like to import all libraries in the header.

The problem is, python 3 script keeps failing to finish if I import os.system or subprocess.run first, then use matlab.engine to connect to matlab. As shown in the code below, my script will be stuck/hanged forever.

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

Screenshot: Screenshot of not working code

Oddly, if I start matlab using either of os.system or subprocess.run without importing matlab.engine as the answer of my previous question suggested, I can start it without any issue.

I also noticed that if I import matlab.engine AFTER started matlab (sample code below), the script will finished. Yet this will make my class very ugly...

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

Screenshot: Screenshot of working code

I tried to bypass this issue by using subprocess.Popen. It did start the matlab and try to use matlab.engine to connect to it without stopping, yet the script can never connect to matlab because matlab.engine will try to connect before matlab finished initializing.

What causes the issue that the script can't finish? How can I import os/subprocess and matlab.engine together in the header? Do I have to make the script stop running for a while in order to wait matlab finished initialization?

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

tamashika
  • 25
  • 5

1 Answers1

2

Here's a solution which:

  • Connects to an existing session if there is one
  • Creates a new session and connects to it if there isn't one

When the Python script ends, our MATLAB session will still be open for future use.


  • For the first case, this is easy. We can simply check for existing sessions with matlab.engine.find_matlab().

  • For the second case, the tricky part is that we cannot use matlab.engine.start_matlab function, because as I mentioned in my previous answer, the lifetime of the MATLAB process is tied to that of the Python process. To avoid this, we want to start MATLAB using Python libraries, for instance using either os or subprocess.

    To then connect to the new running MATLAB, we need to first share the engine from MATLAB, and then connect to it from Python. But to do that, we need the pid, which we can't get straightaway because MATLAB takes some time to start up.

    To get around this, in my solution I am using a simple text file where MATLAB dumps it's pid as soon as it starts. When the file exists, we know MATLAB is ready and thus we can connect to it.


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()

When you run the script, if there is an existing session it will connect to it:

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

If there isn't, it will create one and connect to it:

$ python main.py
Creating new MATLAB session.
Connected to MATLAB_39372!
Paolo
  • 21,270
  • 6
  • 38
  • 69
  • Thanks for answering me again, but do you know why os.system and subprocess.run doesn't work? – tamashika Jun 10 '20 at 23:03
  • Actually it would be easier to use `subprocess.run` over `subprocess.Popen`. I'll post another answer tomorrow – Paolo Jun 10 '20 at 23:07
  • Sorry I wasn't clear about the purpose of keeping my matlab shared session open after the script finishes. I just want to reuse any matlab shared session when it is possible, so I didn't mean to say it has to connect back to the same matlab session when I run the script again. Right now I can use matlab.engine.find_matlab() or subprocess.check_output to check if the matlab (shared or not shared session) is already opened, so I think that part is good. – tamashika Jun 10 '20 at 23:21
  • OK I see. And presumably if there isn't any MATLAB session open, it should open one right? – Paolo Jun 11 '20 at 07:47
  • @tamashika See edited answer. So if a session already exists, it will connect to it. If there isn't, it will create one and connect to it. – Paolo Jun 11 '20 at 08:19
  • Are you creating the pid log because you want to make sure Matlab has finished initialization? – tamashika Jun 11 '20 at 17:03
  • but what could be the reason `subprocess.run` or `os.system` doesn't work? If they work, we don't need to create this log file right? – tamashika Jun 12 '20 at 19:11
  • @tamashika What do you mean `doesn't work`? They work fine! But they don't wait until MATLAB is ready – Paolo Jun 12 '20 at 19:21
  • I added a couple screenshots and hopefully they can help me explain a bit more. The first screenshot shows the script just stuck there and never finished even the matlab is "ready", and that's what I mean by `doesn't work`. The second script can finish without problem (but I did notice that the script finishes without checking weather matlab is ready or not. I think I had a misunderstanding of how `subprocess.run` and `os.system` work). – tamashika Jun 13 '20 at 21:43