【问题标题】:Connect to already running MATLAB with MATLAB Engine使用 MATLAB Engine 连接到已经运行的 MATLAB
【发布时间】:2017-02-03 20:03:32
【问题描述】:

The MATLAB Engine API 允许从 C 程序访问 MATLAB 功能。要设置 MATLAB 引擎会话,请调用 engOpen 函数。默认情况下,这会启动一个新的 MATLAB 实例,专供引擎应用程序使用。

我想要的是使用引擎应用程序中的已经运行的 MATLAB 会话,以便我可以访问其变量。我需要在 Linux 和 OS X 上执行此操作。

Engine 接口在 Windows(它使用 COM 服务器)和 Unix 上的实现非常不同。在 Unix 上,我们必须将 MATLAB 可执行文件的位置传递给 engOpen,而在 Windows(引擎使用 COM 服务器)上,我们不需要。在 Windows 上,可以将现有的 MATLAB 实例用于引擎应用程序:只需运行 enableservice('AutomationServer', true)。 Unix系统上有解决办法吗?

我希望有一个通用的解决方案——也许没有记录——因为based on the documentation, the Python interface seems to allow this。我在 OS X 上对此进行了测试,它可以工作。例如,我可以启动一个交互式 MATLAB 会话,设置一个变量 a=5,然后启动 Python,连接到同一个会话并能够检索这个变量。 It is also possible to connect to an already running session from Java.

我需要从 C 中执行此操作,而不是从 Python,因为它将用于 MATLink,Mathematica-MATLink 接口。 Python 接口是如何实现这一点的?如何使用 C 重现相同的内容?

如果有一个替代 C API 而非“MATLAB 引擎”可以实现这一点(可能是 Python 接口所基于的其他一些已记录或未记录的 C API),我可以接受它作为答案。我想要一个可以利用已经运行的 interactive MATLAB 会话的 C 程序。


更新:

对 Python 界面的一些探索表明它使用了一个名为 libmwengine_api 的库。这与记录在案的 MATLAB Engine C API 不同。我们可以查看这个库中的符号。在 OS X 上,

nm -g libmwengine_api.dylib | c++filt

然后我们可以用 google 搜索这些符号,或者 grep MATLAB 安装目录中包含它们的文件。纯文本中没有任何内容。

基于此,我认为 Python 接口使用了一种未记录的 C++ 引擎 API,它不同于旧的、记录在案的 C 引擎 API。

【问题讨论】:

  • 我觉得如果有替代的API,肯定是和libmwengine_api库相关的。在这个库中列出符号表明它是 C++,而不是 C。这对我来说不是问题,我还是使用 C++。 grepping 整个 MATLAB 安装目录,例如findSharedMATLAB 没有显示任何相关的头文件(只有二进制文件),这强烈表明此接口未记录。
  • 它是很久以前废弃的图书馆的一部分。
  • 你找到答案了吗?
  • @SurajJain 不幸的是,没有。看起来这个替代引擎 API 是通过 C/C++ 的唯一途径,并且没有记录。我不认为你是正确的,它是过时的,因为你的链接提到了其他具有相似但不同名称的库。我认为它从未被记录在案。一种解决方案可能是使用 Java API,它具有所需的功能并已记录在案。 MathWorks 支持人员告诉我,目前无法在 OS X 和 Linux 上使用 C(或 C++)实现我想要的功能。只能在 Windows 上使用。

标签: c linux macos matlab matlab-engine


【解决方案1】:

【讨论】:

  • 感谢您指出这一点。也许过去就是这种情况,但现在可以连接到正在运行的会话。证明是python接口,也被称为“MATLAB引擎”可以在OS X上做到这一点。我刚刚测试过,并相应地更新了问题。也许该解决方案使用了未记录的函数。没关系,我可以接受无证解决方案作为答案。
  • @Szabolcs 我搜索它可能是使用命名管道或套接字或 IPC。这可能是一个有趣的 hack。
  • 我将向 MathWorks 寻求支持并会向您报告。
  • @Szabolcs 我不知道 MATLAB 不是免费的(2000 欧元,我希望他们能得到很好的支持)。祝您搜索顺利。
  • 他们不是很有帮助。正如你所说,我认为没有什么好的方法。
【解决方案2】:

这里是它的 Python Implementation 的源码,看看对你有没有帮助。

一些搜索给我的印象是 libmwengine 是嵌入式系统中使用的库的一部分,并且早已过时。

请参阅This 链接,库libmwengine_api 早就过时了。也许这就是它没有记录的原因。

【讨论】:

  • 看起来这与@Stargateur的答案相同。请在那里查看我的评论。
  • @Szabolcs 所以基本上你是说你希望它在 linux 上工作?
  • 如果我的问题的任何部分令人困惑,请指出。 Python 和 Java 接口可以连接到 OS X 或 Linux 上已经运行的会话。他们是怎么做到的呢?如何使用 MATLAB 提供的任何已记录或未记录的 C API 从 C 复制此内容?
  • @Szabolcs 再看一次。
  • Suraj,我自己编写了 MATLink。我问这个问题是为了改进 MATLink。我希望能够同时拥有两个交互式 MATLAB 和一个 Mathematica 会话,并从其中一个访问 MATLAB 工作区。我正在寻找任何可以在 OS X 和 Linux 上实现这一点的 API。在 Windows 上它已经可以工作了。
【解决方案3】:

我可以在 MacOS 上的命令行中连接到已经运行的 MATLAB 会话(应该可以在任何 Linux 上工作)。我还没有弄清楚如何从 MATLAB IDE 连接到已经运行的 MATLAB 会话 ,但我个人的动机是不必使用 IDE。我让 MATLAB 内核无限期地在后台运行,并根据需要连接到它。这允许我从我的文本编辑器以批处理模式运行 MATLAB 脚本,而不必每次都启动一个新内核。

这就是我的做法。如果您想了解更多详细信息,我很乐意提供完成它的完整脚本:

1。 从 Python 启动 MATLAB 内核/会话。我选择了一个名为 imatlab 的现有 iPython Jupyter Kernel 接口,而不是我发现很难使用的 MATLAB Engine API。我必须安装这个 (pip install imatlab) 以及 Jupyter (pip install jupyter):

from notebook.services.kernels.kernelmanager import MappingKernelManager
m = MappingKernelManager()
m.start_kernel(kernel_name="imatlab")
...

这会在工作目录中创建一个名为kernel-kernel_id.json.json“连接文件”,其中kernel_id 是一个UID(例如4931ac70-e8fd-4d35-81b2-de53e07956c8)。我还将这个内核的名称写入我的 Python 脚本中的一个文件:

id = m.list_kernel_ids()[0]
text_file = open("/Users/Zach/.matlab_kernel/matlab_kernel_name.txt", "w")
text_file.write(id)
text_file.close()

我实际上是在后台 TMUX 会话中执行此操作的,因此我不必打开终端窗口。也很高兴对此发表评论。

2。 使用 Jupyter 的 console 接口连接到这个 MATLAB 内核(尽管我也可以连接一个连接到这个内核的 Jupyter notebook)。首先,我必须从我写入的文件中检索kernel_name

MATLABKERNELNAME=`cat /Users/Zach/.matlab_kernel/matlab_kernel_name.txt`
cd /Users/Zach/.matlab_kernel
jupyter console --existing $MATLABKERNELNAME

我还制作了这个 bash 命令的变体,它打开内核并将命令发送到 MATLAB .m 文件:

mtlb_existing_run_expect(){
        thefilename=`to_abs_path $1`
        thecurrentdirectory=`pwd`
        thekernelname=`cat /Users/Zach/.matlab_kernel/matlab_kernel_name.txt`
        expect <(cat <<EOF
            cd /Users/zach/.matlab_kernel
            spawn jupyter console --existing $thekernelname --simple-prompt --no-confirm-exit && exit
            expect ": "
            send "cd '$thecurrentdirectory'\n"
            expect ": "
            send "run('$thefilename')\n"
            interact -u "exp0"
EOF
)
}

你会注意到我总是cd 进入我启动内核的目录。这是因为 Jupyter 在那里创建了 .json“连接文件”,如果你在目录中,它会自动读取它,并将内核 UID 作为参数提供给 --existing 标志。

我希望这对某人有帮助!

【讨论】:

  • 感谢您抽出宝贵时间回答,但请注意问题是关于使用 MATLAB Engine API。此答案与 MATLAB 引擎无关,对我描述的应用程序没有帮助。
  • 看起来可能是这样,但我非常努力地仅使用 MATLAB 引擎来实现这一点,但找不到方法(在 Unix 上)。我相信没有办法,我什至在 Mathworks 上开了一个问题,因为我强烈认为应该是可能的。事实上,据我所知,没有什么好的方法可以在 MATLAB 中启动引擎,并通过任何语言 API 连接到它,这样您就有了一个实时解释器。另一方面,我的解决方案允许您打开内核并连接到它(通过 iPython,它实现了自己的 REPL 环境),用作 REPL 或运行脚本。
  • 更清楚一点,如果您特别想从外部 MATLAB 内核实现 REPL 环境,MATLAB 引擎绝对没有提供任何机制。你必须从头开始构建它。这让我想到,“也许有人以前构建过 REPL 框架”,这让我想到了 Jupyter/iPython。由于它们不是解释型语言(尽管有 jshell),我怀疑 C/Java 是否有成熟的框架可以结合他们的 MATLAB 引擎 API 来实现这一点。
  • 似乎有一种方法 with the new C++ Engine API认为在 2017 年左右出现了,但我还没有时间调查。这个新的 API 比旧的 C 引擎 API 先进得多。
  • 我不想要 REPL。正如我在问题中所写,这是针对 MATLink 系统的,这是一个 Mathematica 包,可以从 Mathematica 调用 MATLAB。
猜你喜欢
  • 1970-01-01
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 2012-08-31
  • 2016-07-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多