【问题标题】:Slow performance when storing handle objects in a cell array将句柄对象存储在元胞数组中时性能下降
【发布时间】:2011-12-02 08:00:34
【问题描述】:

我的 MATLAB 代码的一小部分存在大量性能问题,希望您能知道如何改进它:

我正在 MATLAB 中开发一个基于代理的模拟,以创建 大量的句柄对象。其中一些是代理,其他可以是例如代理拥有的对象。

为了清楚地识别这些句柄对象中的每一个每一个都有一个唯一的 ID (obj.Id),它由“IdDistributor”对象发出。 IdDistributor 本身被移交给每个对象的构造函数,该构造函数将重新生成一个 Id,并从那里调用以给出一个 Id 编号 (giveId)。

此外,IdDistributor 保留了一种电话簿(IdRegistry),将每个 Id 与对象相关联。因此,给定 Id,可以在 IdRegistry 中查找对象。

我通过使用一个单元数组来实现这一点,该数组将不同的句柄对象存储在与其 Id 完全匹配的字段中。 (普通数组不起作用,因为对象属于不同的类)。

测试我的模拟真的很慢,MATLAB Profiler 显示 99% 的时间都花在了 IdDistributor 上,尤其是在将对象存储在IdRegistry(当我尝试创建大约 10,000 个对象时,每个对象大约需要 1 秒)。

现在我正试图找到一个类似的耗时更少的解决方案。正如您在下面的代码中看到的那样,我已经尝试通过预分配来提高速度(当 IdRegistry 已满时,我将其扩展了 10,000 个单元,而不是按 1 比 1 调整大小)。我还想过尝试以某种方式获取句柄对象的 MATLAB 内部 Id,但当我读到该 Id 不是永久性的并且可以由系统更改时并没有遵循这条路。

我非常感谢任何想法,无论是如何加快代码速度或找到解决方法/改进我的概念!

这是我的代码:

最慢的一行是IdDist.IdRegistry(IdNumber)={obj};

顺便说一句。将其更改为 IdDist.IdRegistry{IdNumber}=obj; 并没有太大帮助

classdef IdDistributor < handle

properties
    Id=int64(1); %Her own ID
    LastId=int64(1);
    IdRegistry={}
end

methods
    function IdDist=IdDistributor()
        IdDist.Id=int64(1);
        IdDist.LastId=int64(1);
        IdDist.register(IdDist);
    end
    function IdNum=giveId(IdDist,obj)
        IdNum=IdDist.LastId+int64(1);
        IdDist.LastId=IdNum;
        IdDist.register(obj,IdNum)
    end
    function register(IdDist,obj,IdNum)
        if nargin==2      
            IdNumber=obj.Id;
        elseif nargin==3
            IdNumber=IdNum;
        end
            if IdNumber>=length(IdDist.IdRegistry) %Extend the Register by 10000
              IdDist.IdRegistry(IdNumber+10000)={[]};    
            end
            if IdNumber >0
              IdDist.IdRegistry(IdNumber)={obj};
            end
    end %function
    end %methods
    end %class

【问题讨论】:

  • 我现在尝试将预分配改为:IdDist.IdRegistry(IdNumber+10000)={SomeDummyHandleObject}; 因为有朋友建议单元格的大小可能会从空单元格 {[]} 更改为存储句柄对象引用的时间,并可能导致 Matlab 重新分配内存。但是,这在 IdDistributor.register 中的 1.428 秒自拍时间中仅节省了 0.009 秒。
  • 运行“慢”时内存消耗如何?您是否可以制作对象的副本而不仅仅是存储句柄?
  • 因为它们都是 Matlab 句柄对象,如果它们被/可以被复制,我会感到惊讶。然而,我刚刚通过将 IdRegistry 的类型从 Cell 更改为 Map 进行了重大改进。我只是要发布我的解决方案,但由于我是新手,stackoverflow 迫使我等待 8 小时。简而言之:属性部分的更改: IdRegistry=containers.Map('KeyType','int64','ValueType','any') ;取出预分配块;注册更改为:IdDist.IdRegistry(IdNumber)=obj; ;现在只需要 17% 的时间。不知道为什么。几个小时后得到完整答案。
  • 即使它们是句柄对象(并且 imo 不应该被复制),我尝试检查内存但发现很难做到,因为对象是在注册时创建的(其中是他们建设的一部分)。
  • 昨天我以为我设法使用 Map 将代码加速了 5 倍(使用 400 个对象进行了测试) - 我使用 10.000 个对象进行了测试一夜之间,它并不比原来的细胞快。于是我又疑惑了。如果我发现新的东西,我会通知您,并感谢您提供任何进一步的建议。

标签: arrays performance oop matlab


【解决方案1】:

由于您没有从注册表中删除对象,您可能想尝试从matlab.mixin.Heterogeneous 类派生所有对象,然后将它们存储为常规数组。请注意,这需要 R2011a 或更高版本。

我不知道这是否更快,但可以尝试一下。当然,只有当您的所有 ID 都由 IdDistributor 生成时,它才会有用,因为它们是连续的。

另外,我的测试表明

length(IdDist.IdRegistry)

也很慢,因此您也可以将注册表的长度存储在IdDistributor 中。为了安全起见,我建议将属性的SetAccess 设置为protected

【讨论】:

  • 真实长度(IdDist.IdRegistry)需要一些时间。当我更新我的程序版本时,我会尝试 minin.Heterogenous。
【解决方案2】:

我进一步调查了这个问题,在我看来,实际上大部分时间都浪费在从不同对象调用 IdDistribute 的 giveId 方法的过程中,而不是在方法内部。

我还发现了我的程序中出现类似问题的其他地方。特别是当许多句柄对象被构造并存储在一个数组中并且这个数组被存储为一个对象的属性时。所以导致性能缓慢的根本原因可能在于这个,因为 IdDistribute 通常在创建新的句柄对象时使用。

由于这是一个有点不同的主题,我发布了另一个question,其中包括一些简单的代码用于说明。

【讨论】:

  • 在我上面列出的new question 下实际上有一些与此问题相关的答案。如果要将同一类的许多对象同时存储在另一个对象的属性中,它们可能会有所帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多