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

Posted

技术标签:

【中文标题】在 Matlab 中从磁盘加载保存的对象很慢【英文标题】:Loading saved objects from disk is slow in Matlab 【发布时间】:2010-07-01 21:02:19 【问题描述】:

我创建了一个怪物,或者至少创建了很多相互指向的 MATLAB 句柄类。例如,实验(句柄)是一组轨道(句柄),其中包含运行(句柄)和重新定向(句柄)。然后轨道指向包含它们的实验,运行和重新定向指向它们来自的轨道,并且它们还指向下一次运行和重新定向的前后。

我已经意识到,在加载或保存文件时,所有这些交叉指向可能会使 MATLAB 感到困惑,所以我尽可能将句柄定义为 Transient 并使用 set.property 方法来定义后面的指针。比如

Track < Handle
   properties(Transient = true)
      expt;
   end
end

Experiment
   properties(AbortSet = true)
      track;
   end
   methods 
      function set.track(obj, value)
          if (~isempty(value) && isa(value, 'Track'))
              value.expt = obj;
          end
          obj.track = value;
   end
end

这似乎加快了从磁盘加载的速度,但我认为我仍然缺少一些东西。

我可以在大约 7 秒内将实验保存到磁盘,创建一个 48 MB 的文件。但是从磁盘加载文件需要 3 分钟。我尝试使用分析器来定位慢点,但它报告的总时间约为 50 毫秒。

问题:

有没有人有将句柄对象保存到磁盘的经验并且可以推荐一般做法来加快加载速度?

有没有什么方法可以让分析器报告 matlab 在另外 179.95 秒内做了什么,或者有系统的方法来确定是什么在不使用分析器的情况下减慢了加载速度?

【问题讨论】:

您忘记附加用于保存和加载数据的代码。如果不知道这段代码,就不可能给你一个有价值的答案。 我正在使用标准的 matlab 保存和加载命令保存文件以保存到 .mat 文件。 Handle 对象的性能一般都很差,见这里:***.com/questions/1446281/matlabs-garbage-collector/… 这篇文章涉及与嵌套句柄相关的内存释放问题。我不确定这是从磁盘加载对象问题的根本原因。我认为我的问题的根本原因是我在 c++/java 行上组织了我的数据,小对象是基本单元,组织成对象数组。 MATLAB 在处理数据数组时要快得多。我的临时解决方案是尽可能多地声明临时字段,然后在加载时重新计算它们,这要快得多。 MATLAB 尝试在每个函数调用上释放内存(运行垃圾收集器),因此两种形式的引用(句柄对象和嵌套函数)的性能都比值对象差。我也不确定这是从磁盘加载对象问题的根本原因。 【参考方案1】:

我不将句柄对象保存到磁盘。相反,我有自定义的保存/加载方法,将句柄对象中的信息复制到结构中以进行保存,我从中构造对象及其对加载的依赖关系。

因此,加载速度相当快,并且我可以有一个补丁方法,允许我在将结构(或其中包含的一些数据)发送到类构造函数之前对其进行更新。

对于分析器问题:我猜 MATLAB 这次在某处显示为“开销”。根据我的经验,很难追查到这一点。

【讨论】:

我认为 MATLAB 支持使用您可以为每个类定义的“saveobj”和“loadobj”方法转换为结构。我可以看到的问题是我不想为每个子类编写这些方法。 这就是为什么我在我的超类中创建了保存和加载方法,它们是继承的。如果某些属性的处理方式与其他属性不同,您可以编写方法以便它们识别方法的不同之处,或者您在每个子类中都有一个隐藏属性来列出“特殊”属性。 但是你如何处理在loadobj方法中调用构造函数呢?例如。酒吧 再一次,我不使用 loadobj 方法。我的加载方法如下所示: 1. 加载结构。 2.constructor = str2fun(loadedStruct.class);,3.obj = constructor(loadedStruct)。换句话说,foo 的 load 方法会加载包含bar 信息的结构体,其中包括一个类名为“bar”的class-field,然后foo 的 load-method 调用bar 的构造函数,结构为输入。 聪明。实际上,我认为这也适用于 saveobj/loadobj 范例,因为 saveobj 也没有理由不能保存类名。【参考方案2】:

我没有使用过句柄对象,但一般来说,保存和加载每个 mxarray 的开销,因此优化 MAT 文件是将其中的数据转换为具有更少 mxarray 的形式的问题。 mxarray 是单级数组结构。例如:

strs = 'foo', 'bar', 'baz';

strs 数组包含 4 个 mxarray:1 个元胞数组和 3 个 char 数组。

要加快保存和加载速度,请尝试在保存时执行此操作,在加载时执行相反操作。 - 将 cellstr 转换为二维字符 - 将记录组织的结构和对象转换为平面组织 - 通过在一个数组中存储一组规范的值并用该数组中的索引替换对象实例来消除冗余对象。 (这可能与句柄无关,它本身就具有这种行为。)

“记录组织”意味着一个包含 N 个事物的数组表示为一个具有标量字段的 N 长结构数组; “平面组织”意味着它被表示为在其字段中包含 N 长数组的标量结构。

看看您是否可以将内存中的对象图转换为适合几个大型原始数组的规范化形式,类似于您在 SQL 中存储它的方式。一组数组中所有对象的对象属性,以及作为数字数组中保存的 (id, id) 元组的句柄关系,可能使用属性数组的索引作为对象 id。

在对象图中的“***”类中定义的 saveobj 和 loadobj 可以进行转换。

此外,如果您使用的是网络文件系统,请尝试使用临时副本在本地文件系统上进行保存和加载。要读取,请将 MAT 文件复制到 tempdir,然后从那里加载();对于写入,save() 到 tempdir,然后将其复制到网络驱动器。根据我的经验,使用本地 I/O 时 save() 和 load() 的速度要快得多,即使有时间进行复制,这也足以带来巨大的净收益(2x-3x 加速)。使用 tempname() 选择临时文件。

对于分析器,您是否使用“-timer real”选项?默认情况下,“profile”显示 CPU 时间,这是以 I/O 为中心的东西。使用“-timer real”,您应该会看到其他 180 秒的挂墙时间归因于 save() 和 load()。不幸的是,由于它们是内置的,分析器不会让您看到它们的内部,这可能没有多大帮助。

【讨论】:

感谢您的提示。我尝试使用 -timer real 标志运行探查器,并获得相同的结果,因为探查器忽略了***内置插件。所以我把加载命令放在一个匿名函数中并再次运行它。如您所料,我得到了有用的结果,即“自用时间(内置、开销等)”占加载时间的 100%。【参考方案3】:

您是否尝试过SAVE 的不同选项,例如-v7.3?我相信使用该格式时会有一些差异。

【讨论】:

我认为有一次我将默认设置设置为 7.3,并且花了足够长的时间来保存我使用任务管理器杀死 MATLAB。其他两种格式(压缩和未压缩)在保存或加载时间方面没有区别。

以上是关于在 Matlab 中从磁盘加载保存的对象很慢的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Matlab 中训练模型,将其保存到磁盘并加载到 C++ 程序中?

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

将矩阵保存在磁盘上以供以后在 Matlab 中使用

matlab如何将对象保存到文件中?

保存或加载图像时 iPhone 设备的响应时间很慢

在 MATLAB 中加载对象