Matlab:在COM服务器上运行函数而不阻塞Matlab?

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秒(无不良影响),然

我正在使用Matlab64位R2011b,我必须使用32位版本(我安装了R2010b)来命令硬件(32位dll)。为此,我使用
actxserver()
创建了一个COM服务器,它可以正常工作

但是,每当函数在32位会话中花费时间时,64位会话将变为“繁忙”,直到完成为止不再工作

我在下面的脚本中简化了我的问题:如果您安装了两个Matlab版本,您可以尝试我的代码并查看我的问题

简言之:

  • 一个按钮启动一个计时器,该计时器仅显示自启动以来经过的时间
  • 另一个按钮在64位会话中暂停2秒(无不良影响),然后在32位会话中暂停2秒(不良影响:计时器停止!)
请提供任何建议,以防止阻塞64位会话

注:我安装了并行计算工具箱,但从未使用过它。R2011b Matlab版本中没有实现
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