【问题标题】:Non-blocking call to external program without losing return code对外部程序的非阻塞调用而不会丢失返回码
【发布时间】:2012-06-01 00:35:01
【问题描述】:

当在 Matlab 中启动外部程序(我们简称为“EX”)时,我可以这样做

[status, result] = system('EX.exe');

在EX返回之前阻塞,或者像这样

[status, result] = system('start EX.exe');

立即返回 Matlab 但无法获取 EX 的返回码。

完成后,如果 EX 的返回码在 Matlab 中仍然可用,那就太好了。这将是调用 Matlab 脚本发现 EX 可能遇到的任何问题的最简单方法。另一方面,我希望 Matlab 在 EX 运行时做其他事情,例如显示进度信息。所以,调用需要是非阻塞的。

我试图通过启动 EX 来解决这个明显的冲突,如上面第一个示例中所述。为了能够在 EX 忙碌时运行其他代码(显示进度信息),我将这段代码放入一个函数中,并使用一个带有小 StartDelay 的计时器来调用它。

不幸的是,这并没有提供真正的多线程(如果没有并行计算工具箱,Matlab 似乎无法实现这一点),即如果计时器回调中的代码运行时间比 EX 长,则执行再次阻塞,直到计时器回调返回。更糟糕的是:由于我不知道 EX 将运行多长时间,因此计时器回调必须无休止地运行,直到它停止或传递一些告诉它停止的标志。我尝试使用全局变量,甚至将此标志存储在应用程序数据中,如下所示:

setappdata(0, 'running', 1);

tim = timer(...
    'StartDelay', 2, ...
    'TimerFcn',   'while getappdata(0, ''running''), fprintf(''timer running ...\n''); pause(1); end' ...
);

fprintf('Starting timer.\n');
start(tim);

fprintf('Calling external program ...\n');
[s,r] = system('EX.exe');
fprintf('External program returned %d.\n', s); % <-- This is never reached.

setappdata(0, 'running', 0);

fprintf('Stopping timer.\n');
stop(tim);
delete(tim);

调用 system() 之后的代码似乎永远不会被执行,并且计时器回调永远运行......有没有其他方法可以让它工作,或者它真的是系统的返回值还是非阻塞调用?

【问题讨论】:

  • 我还不确定如何,但也许您可以使用 MATLAB 中的 Java/.NET 功能来执行异步操作?

标签: matlab


【解决方案1】:

我不确定 MATLAB 是否具有对生成进程的本机/内置支持。不过,您可以使用 MATLAB 中的 Java 来实现它。

例如,

>> runtime = java.lang.Runtime.getRuntime();
>> process = runtime.exec('program arg1 arg2');
>> ...
>>
>>   % when you want to collect results.
>> process.waitFor(); % block until program returns.
>> process.exitValue(); % fetch process return code.
>>
>>   % or, if you need to abandon the work,
>> process.destroy(); % violently kill process

【讨论】:

  • 不确定我是否可以这样做。稍后我将不得不使其成为一个独立的应用程序(使用 Matlab 编译器),并且额外的依赖项不是交易的一部分,即我不能指望在目标机器上安装 Java。据我从 Mathworks 的文档中可以看出,编译器不包含 Java 运行时。因此,该程序需要已经安装了一个。如果我错了,请纠正我。
  • @Atze:确实,尚不清楚生成的程序是否包含 Java 运行时或本地机器上的任何工具箱。您可能需要联系 MathWorks 支持人员以获取更准确的信息。
  • 我设置了一台测试机器,并根据您的代码运行了一个已编译的测试应用程序。测试机器没有安装 Java 运行时。一切正常。我会选择这个解决方案,因为它比文本文件解决方法要干净得多。
  • @Atze:我猜 MATLAB 提供了自己的 Java 运行时。 AFAIK,它需要 Java 来运行解释器,并且许多核心功能都是用 MATLAB 代码编写的。很高兴知道它有效,我需要在不久的将来做同样的事情!
  • MATLAB 提供了自己的 jre,你可以在 MATLABROOT/sys/java/jre 和 MCRROOT/sys/java/jre 中找到它:-)
【解决方案2】:

如果您对其他程序具有编程访问权限,那么目前解决此问题的最简单方法是让其他程序将结果或进度注释保存到文本文件,然后让 matlab 读取。

如果您不能这样做,您可能需要查看parallel computing toolbox。您可以使用一个线程来启动进程并使用另一个线程来监视它。我有一个fewquestions我自己关于如何使用工具箱;尝试他们的示例并在此处发布未来的问题。祝你好运!

【讨论】:

  • 直接生成文件来传递返回值不是一个选项,因为你猜对了,我不能改变 EX。我也没有可用的并行计算工具箱。但是我可以在 Matlab 和 EX 之间添加一个额外的程序。然后这个包装器将调用 EX 并将 EX 的返回值保存到文件中。不如直接从 Matlab 中的调用中获取返回值那么好和干净,但这似乎是一个可以接受的解决方法。
【解决方案3】:

MATLAB 可以进行系统级调用。与其在“并行计算工具箱”上花费 $,不如从其自身调用 matlab。

我的机器有 4 个内核,每个内核有 2 个线程。当我努力工作 MATLAB 时,我只使用了 12.5% 的处理器。所以我开始一次使用多个 MATLAB 实例。

例如。 (在具有多核或超线程的 Windows 机器上)

system('matlab -r "for i=1:1000000000,disp(num2str(i));end;" &'); for i=1:1000000000,disp(num2str(i));end;

在 MATLAB 命令提示符的一行中,这会打开第二个实例,并且都计数到十亿。

代替for i=1:1000000000,disp(num2str(i));end; 参数,给MATLAB 一个函数调用,例如disp('dsfljkhjhkalkhjdfsahjkldahjkdfshjk')。这不允许您轻松获取返回变量,但一个好的解决方法可能是将内容保存在 .mat 文件中。

【讨论】:

  • 嗨凯尔,欢迎来到 StackOverflow!虽然您的信息很有趣,但您最后提出的解决方案似乎是 Atze 在他对 eykanal 的回答的评论中讨论的包装器的一个特例(使用 MATLAB 本身作为包装器)。你是这个意思吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-16
  • 2014-03-23
  • 2012-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多