Matlab:在COM服务器上运行函数而不阻塞Matlab?
我正在使用Matlab64位R2011b,我必须使用32位版本(我安装了R2010b)来命令硬件(32位dll)。为此,我使用Matlab:在COM服务器上运行函数而不阻塞Matlab?,matlab,timer,com,callback,blocking,Matlab,Timer,Com,Callback,Blocking,我正在使用Matlab64位R2011b,我必须使用32位版本(我安装了R2010b)来命令硬件(32位dll)。为此,我使用actxserver()创建了一个COM服务器,它可以正常工作 但是,每当函数在32位会话中花费时间时,64位会话将变为“繁忙”,直到完成为止不再工作 我在下面的脚本中简化了我的问题:如果您安装了两个Matlab版本,您可以尝试我的代码并查看我的问题 简言之: 一个按钮启动一个计时器,该计时器仅显示自启动以来经过的时间 另一个按钮在64位会话中暂停2秒(无不良影响),然
actxserver()
创建了一个COM服务器,它可以正常工作
但是,每当函数在32位会话中花费时间时,64位会话将变为“繁忙”,直到完成为止不再工作
我在下面的脚本中简化了我的问题:如果您安装了两个Matlab版本,您可以尝试我的代码并查看我的问题
简言之:
- 一个按钮启动一个计时器,该计时器仅显示自启动以来经过的时间
- 另一个按钮在64位会话中暂停2秒(无不良影响),然后在32位会话中暂停2秒(不良影响:计时器停止!)
parfeval()
函数(如果有用的话)
timer
+pause
的组合是一种(特殊的)误导性情况,您不应该期望所有操作都具有相同的非阻塞行为
毕竟,MATLAB是一个单线程执行环境(而不是我称之为核心引擎/解释器的部分),尽管它有许多其他用于各种目的的后台线程,如UI或I/O。有一个专用的UI线程,比如Java,对于在长时间操作期间保持IDE的响应性很重要
在pause
调用过程中,某些事件(如窗口重新绘制消息、HG回调、Java事件)会暂停执行。因此,它不是模拟繁重计算负载的理想方法
据我所知,这些计时器对象发出Java事件,这些事件在暂停期间被监听和处理。因此,您的计时器回调函数仍在被调用,这反过来会更新GUI,生成更多的HG事件,这些事件也允许在暂停期间执行
现在,如果您将“64位版本”的pause(2)
替换为实际消耗活动CPU时间的函数调用(例如计算大型矩阵的特征值),您将注意到计时器回调不再在指定的时间间隔上执行
从“64位MATLAB”进程的角度来看,该调用具有相同的性质(在COM服务器中调用的方法),这也将阻塞执行线程
在这两种情况下,您都可以尝试最大化图形窗口这样的调用,并且您将看到,由于主线程忙于运行这些长操作,所以即使窗口重绘消息也没有被及时地调度
这是我的代码修改版本,表明这两种情况都可以阻止MATLAB执行(当前MATLAB进程调用的本地函数或使用COM automation在其他MATLAB进程调用的远程函数):
是否可以在32位版本中执行所有操作,或者您是否对64位R2011b有特定的依赖关系?我认为在32位R2010a上运行2个实验室将是更合理的选择……正如@RodyOldenhuis所说,坚持1个版本似乎是有道理的。不过请注意,最近的版本也发布了32位。如果您必须更改版本,我建议您向上而不是向下。(所以至少使用2011B为32位,但是考虑到最新版本)。谢谢你的评论。我需要使用64位和32位版本的Matlab,因为我命令两个具有特定DLL的设备。它独立于发行版(我想R2010、R2011并不重要)。我只是碰巧安装了这两个,所以我试着这么做。您建议使用同一版本的32位和64位版本吗?我刚刚尝试将'Matlab.Application.7.11'
更改为'Matlab.Application.7.13'
,这意味着我使用相同R2011b 64位版本的两个会话。我想。问题仍然存在,因此不是32位对64位的问题。而是如何使用actxserver
。感谢您的解释。我尝试了你的代码,本地和远程调用都停止了计时器的执行。现在,我应该做些什么来获得相反的行为,即计时器独立于(或者我应该说“并行于”)任何Matlab“繁忙时间”运行?好吧,恐怕你不能,不能保证回调总是按时执行,在事件触发时中断正在运行的任何计算。谢谢你的帮助。我不知道在不接受你的回答的情况下给你奖金是否是一种良好的行为,但这更适合这种情况。
function timer_test
% handles
ha=[];
% create COM server for Matlab 32 bits (change the version accordingly)
ha.matlab32bits = actxserver('Matlab.Application.7.11');
% Create or actualize figure if already open--------------------------
alreadyOpenHandle=findall(0,'Name','TimerTest');
if isempty(alreadyOpenHandle)
ha.f=figure('Position',[400 400 200 140]...
,'Name','TimerTest'...
,'NumberTitle','Off'...
,'MenuBar','none'...
,'Color',[0.94 0.94 0.94] ...
);
else
ha_Old=guidata(alreadyOpenHandle);
ha.f=ha_Old.f;
figure(ha.f); % Bring figure to front
clf % Clear all graphics objects
end
% Buttons-------------------------------------------------------------
ha.button1=uicontrol('Style','Togglebutton' ...
,'Position',[20 80 80 40] ...
,'Parent',ha.f ...
,'String','Run Timer' ...
,'Callback',@button1_Callback ...
);
ha.button2=uicontrol('Style','Pushbutton' ...
,'Position',[100 80 80 40] ...
,'Parent',ha.f ...
,'String','Pause' ...
,'Callback',@button2_Callback ...
);
% Timer--------------------------------------------------------------
ha.myTimer = timer('ExecutionMode', 'fixedRate' ...
,'Period', 0.1 ...
,'TasksToExecute',1000 ...
,'TimerFcn', {@myTimerFcn,ha.f} ... % Specify callback
);
% Text---------------------------------------------------------------
ha.text1=uicontrol('Style','Text' ...
,'Position',[40 20 50 40] ...
,'String','0 s' ...
);
ha.text2=uicontrol('Style','Text' ...
,'Position',[120 20 50 40] ...
,'String','-' ...
);
guidata(ha.f,ha);
%====================================================================
function button1_Callback(hO,ev)
ha=guidata(findall(0,'Name','TimerTest'));
if get(ha.button1,'Value')==1
start(ha.myTimer);
else
stop(ha.myTimer);
end
function button2_Callback(hO,ev)
ha=guidata(findall(0,'Name','TimerTest'));
% pause the 64-bit matlab (timer still running, ok)
set(ha.text2,'String','Paused in 64bits');
pause(2);
% pause the 32-bit matlab (timer halts !!)
set(ha.text2,'String','Paused in 32bits');
drawnow;
ha.matlab32bits.Execute('pause(2)');
% end
set(ha.text2,'String','-');
function myTimerFcn(obj,ev,f)
drawnow;
ha=guidata(findall(0,'Name','TimerTest'));
elapsed=[num2str(roundn(obj.TasksExecuted/10,-1),'%4.1f') ' s'];
set(ha.text1,'string',elapsed);
function timer_test
% h is a handles structure shared with the nested functions
h = create_gui();
h.actx = actxserver('Matlab.Application.8.2');
h.timer = timer('ExecutionMode', 'fixedRate', 'Period',0.1, ...
'BusyMode','drop', 'TasksToExecute',1000, 'TimerFcn',@timer_cb);
function toggle_btn_cb(o,~)
% start/stop timer
if get(o, 'Value') == 1
start(h.timer);
else
stop(h.timer);
set(h.txt1, 'String','0'); drawnow
end
end
function run_btn_cb(~,~,mode)
set(h.btns, 'Enable','off')
if strcmp(mode,'local')
% local call
set(h.txt2, 'String','Locally'); drawnow
tic
eig(rand(2000));
toc
elseif strcmp(mode,'remote')
% remote call
set(h.txt2, 'String','Remotely'); drawnow
tic
%Feval(h.actx, 'pause', 0, 5);
Execute(h.actx, 'pause(5);');
toc
end
set(h.btns, 'Enable','on')
% reset text
set(h.txt2,'String',''); drawnow
end
function timer_cb(~,~)
% abort if figure was closed
if ~ishghandle(h.fig)
try stop(h.timer); delete(h.timer); end
return
end
% update counter
set(h.txt1, 'String',sprintf('%d', h.timer.TasksExecuted))
drawnow
end
function handles = create_gui()
% build the GUI
hfig = figure('Menu','none', 'Position',[400 400 275 140]);
uicontrol('Style','togglebutton', 'String','Start/Stop', ...
'Parent',hfig, 'Position',[20 80 80 40], ...
'Callback',@toggle_btn_cb);
hbtn1 = uicontrol('Style','pushbutton', 'String','Local Call', ...
'Parent',hfig, 'Position',[100 80 80 40], ...
'Callback',{@run_btn_cb,'local'}, 'Interruptible','on');
hbtn2 = uicontrol('Style','pushbutton', 'String','Remote Call', ...
'Parent',hfig, 'Position',[180 80 80 40], ...
'Callback',{@run_btn_cb,'remote'}, 'Interruptible','on');
htxt1 = uicontrol('Style','text', 'String','0', ...
'Parent',hfig, 'Position',[50 20 60 20]);
htxt2 = uicontrol('Style','text', 'String','', ...
'Parent',hfig, 'Position',[130 20 100 20]);
handles = struct('fig',hfig, 'btns',[hbtn1,hbtn2], ...
'txt1',htxt1, 'txt2',htxt2);
end
end