注意: 此问题涉及 2011 年观察到的旧 MATLAB 版本 (R2009a) 的问题。根据以下 2016 年 7 月的更新,MATLAB 中的问题/错误似乎不再存在(使用 R2016a 测试;向下滚动到问题末尾以查看更新)。
我正在使用 MATLAB R2009b,我需要编写一个更大的脚本,将一组更大的 .zip 文件的内容转换为 v7.3 mat 文件(具有底层 HDF5 数据模型)。读书没问题。问题在于储蓄。而且实际上没有问题。我的文件使用save命令保存得很好。
我的问题更有意义:为什么我在 MATLAB 中观察到以下令人惊讶的(对我而言)行为?
让我们看一下我的一般问题。在当前的测试场景中,我将生成一个输出:A -v7.3 mat-file。这个 .mat 文件将包含 40个块作为单独的变量。每个变量将被命名为从 1 到 40 的“block_NNN”,并将包含一个带有字段frames和blockNo的结构。字段帧包含 480x240x65 的 uint8 图像数据序列(这里只是使用randi生成的随机数据)。字段blockNo包含块号。
备注:在真正的脚本中(我还没有完成)我将总共执行 370 次以上操作,转换总共 108GB 的原始数据。这就是为什么我关心以下内容。
无论如何,首先我定义一些通用变量:
% 一些大小的虚拟数据和循环: num_blockCount = 40; num_blockLength = 65; num_frameHeight = 480; num_frameWidth = 240;
然后我生成一些形状和大小与实际原始数据相同的虚拟代码:
% 生成空结构: stu_data2disk = 结构(); % 循环块: 对于 num_k = 1:num_blockCount % 生成块名: temp_str_blockName = sprintf('block_%03u', num_k); % 为当前块生成临时结构: temp_stu_value = 结构(); temp_stu_value.frames = 兰迪(... [0 255], ... [num_frameHeight num_frameWidth num_blockLength], ... 'uint8' ... ); temp_stu_value.blockNo = num_k; % 使用动态字段名称: stu_data2disk.(sprintf('block_%03u', num_k)) = temp_stu_value; 结尾
我现在将所有随机测试数据都放在 struct stu_data2disk中。现在我想使用两种可能的方法之一来保存数据。
让我们先尝试一个简单的:
% 保存数据(简单): disp('保存数据的简单方法:') 抽动; 保存转换后的.mat -struct stu_data2disk -v7.3; 目录;
该文件写入没有问题(286MB)。输出是:
以简单的方式保存数据: 经过的时间是 14.004449 秒。
好的 - 然后我记得我想在 40 个块上遵循保存程序。因此,我不是上面的,而是遍历块并按顺序附加它们:
% 保存到文件,使用追加: disp('保存数据使用 -append:') 抽动; 对于 num_k = 1:num_blockCount % 生成块名: temp_str_blockName = sprintf('block_%03u', num_k); temp_str_appendToggle = ''; 如果 (num_k > 1) temp_str_appendToggle = '-追加'; 结尾 % 生成保存命令: temp_str_saveCommand = [ ... '节省 ', ... 'converted_append.mat', ... '-struct stu_data2disk',temp_str_blockName,''... temp_str_appendToggle, ' ', ... '-v7.3', ... ';' ... ]; % 评估保存命令: 评估(temp_str_saveCommand); 结尾 目录;
该文件再次保存得很好(286MB)。输出是:
使用 -append 保存数据: 经过的时间是 0.956968 秒。
有趣的是,附加方法要快得多?我的问题是为什么?
输出dir converted*.mat
:
09-02-2011 20:38 300,236,392 转换.mat 2011 年 9 月 2 日 20:37 300,264,316 convert_append.mat 2 个文件 600,500,708 字节
这些文件的大小不相同。在 Windows 7 中使用fc进行的测试显示......很多二进制差异。也许数据被转移了一点——因此这并没有告诉我们什么。
有人知道这里发生了什么吗?附加文件是否使用了更优化的数据结构?或者,也许 Windows 已经缓存了文件并使其访问速度更快?
我也努力从这两个文件中进行测试读取。如果不在这里显示数字,附加版本会更快一些(但从长远来看可能意味着什么)。
[编辑]:我只是尝试使用无格式标志(在我的系统上默认为 -v7)并且没有太大区别了:
以简单的方式保存数据(-v7): 经过的时间是 13.092084 秒。 使用 -append (-v7) 保存数据: 经过的时间是 14.345314 秒。
[编辑]:我纠正了上述错误。之前我提到统计数据是针对 -v6 的,但我错了。我刚刚删除了格式标志并假设默认值为 -v6 但实际上它是 -v7。
我使用 Andrew 的精细框架为我的系统上的所有格式创建了新的测试统计信息(所有格式都用于相同的随机测试数据,现在从文件中读取):
15:15:51.422:测试速度,格式=-v6,PCWIN 上的 R2009b,arch=x86,os=Microsoft Windows 7 Professional 6.1.7600 N/A Build 7600 15:16:00.829:保存简单方法:0.358 秒 15:16:01.188:使用多个附加保存:7.432 秒 15:16:08.614:使用一个大附加保存:1.161 秒 15:16:24.659:测试速度,格式=-v7,PCWIN 上的 R2009b,arch=x86,os=Microsoft Windows 7 Professional 6.1.7600 N/A Build 7600 15:16:33.442:保存简单方法:12.884 秒 15:16:46.329:使用多个附加保存:14.442 秒 15:17:00.775:使用一个大附加保存:13.390 秒 15:17:31.579:测试速度,格式=-v7.3,PCWIN 上的 R2009b,arch=x86,os=Microsoft Windows 7 Professional 6.1.7600 N/A Build 7600 15:17:40.690:保存简单方法:13.751 秒 15:17:54.434:使用多个附加保存:3.970 秒 15:17:58.412:使用一个大追加保存:6.138 秒
以及文件的大小:
2011 年 2 月 10 日 15:16 299,528,768 转换格式-v6.mat 2011 年 2 月 10 日 15:16 299,528,768 转换_append_format-v6.mat 10-02-2011 15:16 299,528,832 转换_append_batch_format-v6.mat 2011 年 2 月 10 日 15:16 299,894,027 转换格式-v7.mat 2011 年 2 月 10 日 15:17 299,894,027 转换的_append_format-v7.mat 10-02-2011 15:17 299,894,075 转换_append_batch_format-v7.mat 10-02-2011 15:17 300,236,392 convert_format-v7.3.mat 10-02-2011 15:17 300,264,316 convert_append_format-v7.3.mat 10-02-2011 15:18 300,101,800 转换_append_batch_format-v7.3.mat 9 个文件 2,698,871,005 字节
因此 -v6 似乎是最快的编写方式。文件大小也没有太大差异。据我所知,HDF5 确实内置了一些基本的膨胀方法。
嗯,可能是对底层 HDF5 写入函数的一些优化?
目前我仍然认为一些底层的基本 HDF5 写入函数已针对将数据集添加到 HDF5 文件进行了优化(这是在将新变量添加到 -7.3 文件时发生的情况)。我相信我已经在某处读到 HDF5 应该以这种方式优化......虽然不能确定。
其他需要注意的细节:
正如我们在下面安德鲁的回答中看到的那样,这种行为非常系统化。至于您是在函数的本地范围内还是在 m 脚本的“全局”范围内运行这些东西,这似乎也很重要。我的第一个结果来自将文件写入当前目录的 m 脚本。我仍然只能在 m 脚本中重现 -7.3 的 1 秒写入。函数调用显然增加了一些开销。
2016 年 7 月更新:
我再次找到了这个,并认为我可以使用目前可用的最新 MATLAB 对其进行测试。在 Windows 7 x64 上使用 MATLAB R2016a,问题似乎已得到解决:
14:04:06.277: 测试速度, imax=255, R2016a on PCWIN64, arch=AMD64, 16 GB, os=Microsoft Windows 7 Enterprise Version 6.1 (Build 7601: Service Pack 1) 14:04:10.600:基本 -v7.3:7.599 秒 5.261 GB 已使用 14:04:18.229:基本 -v7.3:7.894 秒 5.383 GB 已使用 14:04:26.154:基本 -v7.3:7.909 秒 5.457 GB 已使用 14:04:34.096:基本 -v7.3:7.919 秒 5.498 GB 已使用 14:04:42.048:基本 -v7.3:7.886 秒 5.516 GB 使用 286 MB 文件 7.841 秒平均值 14:04:50.581:multiappend -v7.3:7.928 秒 5.819 GB 已使用 14:04:58.544:multiappend -v7.3:7.905 秒 5.834 GB 已使用 14:05:06.485:multiappend -v7.3:8.013 秒 5.844 GB 已使用 14:05:14.542:multiappend -v7.3:8.591 秒 5.860 GB 已使用 14:05:23.168: multiappend -v7.3: 8.059 sec 5.868 GB used 286 MB file 8.099 sec mean 14:05:31.913: bigappend -v7.3: 7.727 秒 5.837 GB 已使用 14:05:39.676: bigappend -v7.3: 7.740 秒 5.879 GB 已使用 14:05:47.453: bigappend -v7.3: 7.645 秒 5.884 GB 已使用 14:05:55.133: bigappend -v7.3: 7.656 秒 5.877 GB 已使用 14:06:02.824: bigappend -v7.3: 7.963 sec 5.871 GB used 286 MB file 7.746 sec mean
这在下面接受的答案中使用 Andrew Janke 的reproMatfileAppendSpeedup
函数进行了测试(5 次通过,格式为 7.3)。现在,-append
对于单次保存来说同样慢,或者更慢 - 应该是这样。可能是 R2009a 中使用的 HDF5 驱动程序的早期版本存在问题。