创建句柄对象数组作为对象属性时如何避免Matlab花费指数时间

Posted

技术标签:

【中文标题】创建句柄对象数组作为对象属性时如何避免Matlab花费指数时间【英文标题】:How to avoid Matlab taking exponential time when creating a handle object array as an object property 【发布时间】:2011-12-05 07:18:12 【问题描述】:

在我看来,当在 Matlab 中创建一个简单句柄对象数组时,时间尺度大约是线性的。但是,如果我创建完全相同的数组并将其存储为对象的属性,时间会呈指数级增长 - 因此,当创建许多对象时,程序会变得非常慢。

我的问题是为什么会发生这种情况以及如何避免这种情况? 对象属性的预分配是否未在我的代码中正确实现,还是 Matlab 处理这些事情的方式存在根本问题?

我写了一个简单的测试来说明这个问题:

简单对象代码:

classdef SomeSimpleObject < handle
% SomeSimpleObject defines an Object that has one property

properties
    property=0;
end

methods
    function SimpleObj=SomeSimpleObject()
        if nargin~=0
            SimpleObj.property=1;
        end
    end
end

end

使用以下脚本创建这些简单对象的 1x10.000 数组需要根据我的机器上的分析器 0.4 秒:

for n=10000:-1:1 % counting backwards for Memory pre-allocation
    ObjectList(n)=SomeSimpleObject();
end

但是,在类构造函数中执行相同的操作并将 10.000 个对象的数组存储为一个属性需要 59 秒,而且很快就会变得更糟。通过从此类创建一个对象来尝试它(例如 a=HostingObject

classdef HostingObject < handle
% This Objects Hosts a List of Objects that are created in the
% constructor

properties
    ObjectList=SomeSimpleObject
end

methods
    function obj=HostingObject()    
        for n=10000:-1:1 % counting backwards for Memory pre-allocation
            obj.ObjectList(n)=SomeSimpleObject();
        end
    end
end

end

寻找答案我遇到了关于 Matlab 内存分配和garbage collection 的讨论。 Mikhail 的答案(也与我的问题没有直接关系)让我认为这可能是 Matlab 实现对象方式的一个根本问题,但我仍然不确定。

【问题讨论】:

读者注意:另见Jacobs' previous related question,它激发了这一点 我认为您将 MATLAB 推向了极限,MATLAB 不是为这种用途而开发的。在我被 MATLAB GC ***.com/questions/1446281/matlabs-garbage-collector 烧毁后,我使用了 C#,因为从未回头 - ***.com/questions/5042761/… 【参考方案1】:

我不知道为什么您的代码很慢,但我找到了解决方法:使用 单元格数组 而不是普通数组。我自己并不觉得它完全直观,但这是我的分析结果:

>> tic,a=HostingObject;toc
Elapsed time is 105.320128 seconds.

>> tic,a=JonasHostingObject;toc
Elapsed time is 2.394570 seconds.

对象定义如下:

classdef JonasHostingObject < handle
properties
    ObjectList
end
methods
    function obj=JonasHostingObject()    
        obj.ObjectList=cell(10000,1);
        for n=1:10000
            obj.ObjectListn=SomeSimpleObject();
        end
    end
end    
end

我正在使用 MATLAB R2011a 64 位,以防万一。

【讨论】:

除非您存储不同的数据类型,否则使用元胞数组是一种不好的做法。【参考方案2】:

受到@Jonas Heidelberg 和@Tobias Heß 答案的启发,我想出了以下根本不需要单元阵列的解决方案。对象存储在辅助数组中,一旦完成,它们就会被复制到属性数组中:

带有数组“分配后”的 HostingObject 代码:

classdef JacobHostingObject < handle
% This Objects Hosts a List of Objects that are created in the constructor

properties
    ObjectList=SomeSimpleObject
end

methods
    function obj=JacobHostingObject()         
        for n=10000:-1:1 % counting backwards for Memory pre-allocation         
            a(n)=SomeSimpleObject(); % auxiliary array for "post-allocation"           
        end            
         obj.ObjectList=a; % "post-allocation"
    end
end

end

那么三种解决方案(Jonas、Tobias 和我的)表现如何?

我运行了一些测试(使用 MATLAB R2011b 64 位)来比较它们:

10.000 个对象

经过时间:托比亚斯:0,30 秒;雅各布:0,31 秒;乔纳斯:2.02 秒;原文:56.79 秒

100.000 个对象

经过时间:托比亚斯:2.42 秒;雅各布:2,95 秒;乔纳斯:203,03 秒

1.000.000 个对象

经过时间:托比亚斯:23,84 秒;雅各布:29,18 秒

所以看起来 Tobias 版本是最快的解决方案

值得注意的是,Jonas 解决方案比原来的解决方案要好得多,但与其他两个解决方案相比则要差得多。这证实了我在之前的问题"slow performance when storing handle objects in a cell array" 中所做的观察。具有讽刺意味的是,使用导致我早期问题的技术竟然是对这个问题的改进。然而,Tobias 解决方案甚至也回答了我的老问题(我将在此处发布参考)。

但是,仍然不清楚 MATLAB 内部究竟发生了什么导致性能差异。了解这一点可能会有所帮助,以避免将来遇到类似的问题!

【讨论】:

很好的比较...我还观察到在使用大量句柄时 Matlab 的非常奇怪的行为。 Stortly 安装了 som 认为现在可以工作的 Matlab 2011b,因此对未来的发展有希望 用更复杂的对象测试这个使我的版本使用简单数组而不是单元数组和horzcat(cell:)比Tobias'快得多。在特定情况下,Tobias 需要 66 秒,而我的解决方案需要 0.8 秒。所以值得测试一下哪个对你来说更快。【参考方案3】:

我找到了另一个答案。我认为使用单元格数组不是一个好的解决方案,因为您对对象的访问权限与数组中的不同。但是您可以使用单元格作为解决此问题的方法:

classdef HostingObject < handle
% This Objects Hosts a List of Objects that are created in the
% constructor

properties
    ObjectList=SomeSimpleObject
end

methods
    function obj=HostingObject()

        % Creating first a cell array
        helpCell = cell(10000,1);
        for n=1:10000 
            helpCelln=SomeSimpleObject();
        end

        % Convert the cell array to the object array
        obj.ObjectList = horzcat(helpCell:);

    end

end

end

【讨论】:

没错,对象数组比元胞数组更方便。然而,您的解决方案(使用辅助元胞数组)也比直接写入属性快得多。请参阅我的答案中的性能比较。 不幸的是,我刚刚发现这并不总是最好的解决方案。对于要存储在属性中的更复杂的对象,我的数组解决方案更快。谁知道为什么?

以上是关于创建句柄对象数组作为对象属性时如何避免Matlab花费指数时间的主要内容,如果未能解决你的问题,请参考以下文章

在 MATLAB 中删除对象句柄并保留变量

matlab中的set命令怎么用啊

在 Matlab 中从磁盘加载保存的对象很慢

在 Matlab 类对象数组上调用 delete

MATLAB图形界面设计(上)

如何在matlab中将句柄对象层次结构保存到磁盘