我需要编写一个太大的数组,无法将内存放入.mat二进制文件中。这可以通过matfile
函数来完成,该函数允许随机访问磁盘上的.mat文件。
通常,接受的建议是预分配数组,因为在循环的每次迭代中扩展它们都很慢。但是,当我asking how to do this时,我发现在写入磁盘而不是RAM时,这可能不是一个好建议。
增长阵列适用的性能是否相同,如果那么, 显着< / em> 什么时候与写入磁盘的时间相比呢?
(假设整个文件将写入一个会话,因此严重文件碎片的风险为 低 。)
答案 0 :(得分:7)
问:阵列增长会产生相同的性能影响,如果是这样,那么与写入磁盘所需的时间相比是否会很重要?
答:是的,如果您在没有预先分配的情况下显着增加磁盘上的文件,性能将受到影响。性能受到影响将是碎片化的结果。正如您所提到的,如果文件是在一个会话中编写的,则碎片风险较小,但如果文件显着增长则会导致问题。
MathWorks网站上提出related question,接受的答案是尽可能预先分配。
如果您没有预先分配,那么您的效果问题的程度将取决于:
让我们假装您正在运行最近的Windows操作系统,因此使用NTFS file-system。让我们进一步假设它已经设置了默认的4 kB簇大小。因此,磁盘上的空间将在4 kB chunks中分配,并且这些位置将被索引到主文件表。如果文件增长且连续空间不可用,则只有两个选择:
文件系统选择执行最不好的选项#2,并更新MFT记录以指示新群集在磁盘上的位置。
现在,硬盘需要物理移动读头以便读取或写入新簇,这是一个(相对)慢的过程。在移动头部,并等待盘的正确区域在其下旋转......你可能正在寻找about 10ms的寻道时间。因此,每次敲击碎片时,HDD都会有额外的10ms延迟,以便访问新数据。 SSD具有更短的寻道时间(没有移动部件)。为简单起见,我们忽略了多盘系统和RAID阵列!
如果您在不同时间继续增长文件,那么您可能会遇到很多碎片。这实际上取决于文件的增长时间/数量,以及您使用硬盘的方式。您遇到的性能影响还取决于您阅读文件的频率以及您遇到片段的频率。
MATLAB将数据存储在Column-major order中,并且根据评论,您似乎对在数据集上执行逐列操作(总和,平均值)感兴趣。如果列在磁盘上变得不连续,那么您将在每次操作时击中大量碎片!
如评论中所述,读取和写入操作都将通过缓冲区执行。正如@ user3666197指出的那样,操作系统可以推测性地预先读取磁盘上的当前数据,因为您可能希望接下来需要这些数据。如果硬盘有时处于空闲状态 - 保持其以最大容量运行并且在缓冲存储器中处理小部分数据可以极大地提高读写性能,则此行为尤其有用。但是,从你的问题来看,听起来好像你想对一个巨大的(太大的内存).mat文件执行大型操作。鉴于您的用例,硬盘将以容量无论如何工作,并且数据文件太大而无法容纳缓冲区 - 因此这些特殊技巧无法解决您的问题
所以......是的,你应该预先分配。是的,在磁盘上增加阵列的性能会受到影响。是的,它可能会很重要(这取决于具体的增长量,碎片等)。如果你真的 进入HPC的精神状态,那就停止你正在做的事情,抛弃MATLAB,破坏你的数据并尝试类似Apache Spark的东西!但这是另一个故事。
这会回答你的问题吗?
P.S。更正/修改欢迎!我是在POSIX inode上长大的,如果这里有任何不准确之处,我真诚地道歉......
答案 1 :(得分:2)
在RAM中预先分配变量并在磁盘上预分配不能解决同样的问题。
为了在RAM中扩展矩阵,MATLAB创建一个具有新大小的新矩阵,并将旧矩阵的值复制到新矩阵中并删除旧矩阵。这会花费很多性能。
如果您预先分配了矩阵,则其大小不会改变。所以没有理由让MATLAB再次进行矩阵复制。
GnomeDePlume说,硬盘上的问题是碎片。即使文件是在一个会话中编写的,碎片仍然是一个问题。
原因如下:硬盘通常会有点碎片化。想象一下
#
是硬盘上已满的内存块M
是硬盘上用于保存矩阵数据的内存块-
是硬盘上的空闲内存块现在,在将矩阵写入其中之前,硬盘看起来像这样:
###--##----#--#---#--------------------##-#---------#---#----#------
当您编写矩阵的某些部分(例如MMM
块)时,您可以想象这个过程看起来像这样&gt;!(我举一个例子,文件系统将从左到右依次使用第一个足够大的可用空间 - 真正的文件系统是不同的):
###--##MMM-#--#---#--------------------##-#---------#---#----#------
###--##MMM-#--#MMM#--------------------##-#---------#---#----#------
###--##MMM-#--#MMM#MMM-----------------##-#---------#---#----#------
显然,硬盘上的矩阵文件是碎片化的,尽管我们在此期间没有做任何其他事情的情况下编写它。
如果矩阵文件已预先分配,这可能会更好。换句话说,我们告诉文件系统我们的文件有多大,或者在这个例子中,我们要为它保留多少内存块。
想象一下矩阵需要12个块:MMMMMMMMMMMM
。我们通过预先分配告诉文件系统我们需要这么多,它将尽可能地满足我们的需求。在这个例子中,我们很幸运:有一个带有&gt; = 12个内存块的可用空间。
###--##----#--#---# (------------) --------##-#---------#---#----#------
###--##----#--#---# (MMM---------) --------##-#---------#---#----#------
###--##----#--#---# (MMMMMM------) --------##-#---------#---#----#------
###--##----#--#---# (MMMMMMMMM---) --------##-#---------#---#----#------
###--##----#--#---# (MMMMMMMMMMMM) --------##-#---------#---#----#------
Voilá,没有碎片!
一般来说,您可以将此过程想象为购买大型团体的电影票。你想团结在一起,但是剧院里已经有一些座位由其他人保留。为了使收银员能够满足您的要求(大型团队想要团结在一起),他/她需要了解您的团队有多大(预分配)。
答案 2 :(得分:2)
对整个讨论的快速回答(如果您没有时间关注或技术理解):
因此,如果你不能一次性写,将写入分成大块。
答案 3 :(得分:-3)
此答案基于作者在最近一周提供的原始帖子和澄清(两者)。
不良效果的问题(s)由引入的低级别,依赖于物理媒体,&#34;碎片&#34; ,由文件系统&amp;文件访问层在TimeDOMAIN幅度和这些的这些的这些的ComputingDOMAIN重复性中进一步面对。
最后提出了针对特定任务的最新,主要最快的解决方案,以便最大限度地减少浪费的努力和错误解释错误造成的损害从理想化或其他无效假设,类似于严重文件碎片的风险很低&#34;由于一个假设,整个文件将在一个会话中写入(在当前O / S的许多多核/多进程操作中实时过度,主要是不可能在当代COTS文件系统中,TB大小的BLOB文件对象的创建时间和一系列广泛的修改(参考MATLAB大小限制)。
有人可能会讨厌事实,但事实仍然存在,直到更快和更快。
更好的方法真正的性能不利影响是HDD-IO 造成或与文件碎片有关
对于 .mat
文件
<强>假设:强>
整个处理只是运行一次,没有优化/迭代,没有连续处理
数据 1E6
double
浮动值 x 1E5
columns =关于 0.8 TB
(+ HDF5
开销)
尽管有原始帖子,但没有随机IO 与处理相关
数据获取阶段与.NET通信,以便将DataELEMENT
s 接收到MATLAB
这意味着,自v7.4起,
1.6 GB limit
, MATLAB WorkSpace ,32位胜利(2.7 GB,3GB开关)
1.1 GB limit
, MATLAB最大矩阵,wXP / 1.4 GB wV / 1.5 GB
2.6 GB limit
。
拥有64位O / S无助于任何类型的32位MATLAB 7.4实现,而将无法工作,因为另一个限制,即阵列中的最大单元数,这不会覆盖1E12在这里要求。
唯一的机会是两者
和 64位MATLAB 7.5 +
MathWorks' source for R2007a cited above, for newer MATLAB R2013a you need a User Account there
数据存储阶段假定行排序数据块(行排序数据块的集合)的块写入到HDD设备上的MAT-file
< / p>
数据处理阶段假定在获取所有输入并将所有输入编组到基于文件的关闭后,重新处理HDD设备上的MAT-file
中的数据-RAM存储,但按列顺序排列
只需逐列mean()
- s / max()
- 需要计算(没有更复杂的)
<强>事实:强>
HDF5
文件结构。分层数据格式(HDF
)于20年前诞生于1987年的国家超级计算应用中心( NCSA )。是的,那个老了。目标是开发一种文件格式,结合 灵活性 和 效率 来处理极大的数据集。不知何故HDF文件没有在主流中使用,因为只有少数几个行业确实能够真正利用它的可怕的容量或者根本不需要它们。
灵活性意味着文件结构带来一些开销,如果阵列内容没有变化,则无需使用(您支付成本而不消耗任何好处使用它)和一个假设,HDF5
限制数据的整体大小,它可以包含一些帮助和保存MATLAB方面的问题是不正确的。
MAT-files
原则上是好的,因为它们可以避免将整个文件加载到RAM中以便能够使用它。
然而,MAT-files
并不能很好地完成这里定义和澄清的简单任务。尝试这样做会导致性能不佳和HDD-IO文件碎片(在 write-through
-s期间添加几十毫秒,而在上添加的内容少于几十毫秒在计算过程中read-ahead
-s对判断整体业绩不佳的核心原因毫无帮助。
而不是将整个巨大的 1E12
DataELEMENT
集合移动到MATLAB内存代理数据阵列中,而不是将其安排在下一个即将到来的序列流中。 HDF5
/ MAT-file
HDD设备IO-s(write-through
和O / S与硬件 - 设备链冲突/次优化read-ahead
s)以便让所有的巨大工作&#34;只是[已婚]准备好&#34;为了几个&amp;简单地调用 mean()
/ max()
MATLAB函数(将尽力修改每个 1E12
DataELEMENT
只是另一个订单(甚至两次 - 是 - 另一个马戏团,在第一次工作处理噩梦一路下来之后,通过所有HDD-IO瓶颈)重新进入MATLAB in-RAM-objects,重新设计这一步从一开始就进入管道BigDATA处理。
while true % ref. comment Simon W Oct 1 at 11:29
[ isStillProcessingDotNET, ... % a FLAG from .NET reader function
aDotNET_RowOfVALUEs ... % a ROW from .NET reader function
] = GetDataFromDotNET( aDtPT ) % .NET reader
if ( isStillProcessingDotNET ) % Yes, more rows are still to come ...
aRowCOUNT = aRowCOUNT + 1; % keep .INC for aRowCOUNT ( mean() )
for i = 1:size( aDotNET_RowOfVALUEs )(2) % stepping across each column
aValue = aDotNET_RowOfVALUEs(i); %
anIncrementalSumInCOLUMN(i) = ...
anIncrementalSumInCOLUMN(i) + aValue; % keep .SUM for each column ( mean() )
if ( aMaxInCOLUMN(i) < aValue ) % retest for a "max.update()"
aMaxInCOLUMN(i) = aValue; % .STO a just found "new" max
end
endfor
continue % force re-loop
else
break
endif
end
%-------------------------------------------------------------------------------------------
% FINALLY:
% all results are pre-calculated right at the end of .NET reading phase:
%
% -------------------------------
% BILL OF ALL COMPUTATIONAL COSTS ( for given scales of 1E5 columns x 1E6 rows ):
% -------------------------------
% HDD.IO: **ZERO**
% IN-RAM STORAGE:
% Attr Name Size Bytes Class
% ==== ==== ==== ===== =====
% aMaxInCOLUMNs 1x100000 800000 double
% anIncrementalSumInCOLUMNs 1x100000 800000 double
% aRowCOUNT 1x1 8 double
%
% DATA PROCESSING:
%
% 1.000.000x .NET row-oriented reads ( same for both the OP and this, smarter BigDATA approach )
% 1x INT in aRowCOUNT, %% 1E6 .INC-s
% 100.000x FLOATs in aMaxInCOLUMN[] %% 1E5 * 1E6 .CMP-s
% 100.000x FLOATs in anIncrementalSumInCOLUMN[] %% 1E5 * 1E6 .ADD-s
% -----------------
% about 15 sec per COLUMN of 1E6 rows
% -----------------
% --> mean()s are anIncrementalSumInCOLUMN./aRowCOUNT
%-------------------------------------------------------------------------------------------
% PIPE-LINE-d processing takes in TimeDOMAIN "nothing" more than the .NET-reader process
%-------------------------------------------------------------------------------------------
您的管道 d BigDATA计算策略将以智能方式主要避免 MATLAB中的临时存储缓冲,因为它将逐步计算结果不超过< strong> 3 x 1E6
ADD / CMP寄存器,均采用静态布局,避免代理存储到HDF5
/ MAT-file
,绝对避免所有与HDD-IO相关的瓶颈和低BigDATA持续读取&#39;速度(完全没有谈到临时/ BigDATA持续写入......)并且也会避免表现不佳的内存映射用于计算mean-s和max-es。
在太阳下,管道处理并不是什么新鲜事。
它重复使用速度导向的HPC解决方案已经使用了几十年
[BigDATA标签之前的几代人已经发明了#34;#34;在营销部门。 ]
忘掉数以万计的HDD-IO阻塞操作&amp;进入流水线分布式流程到流程解决方案。
如果,所有外汇业务和HFT对冲基金怪兽都已经在那里......