簡體   English   中英

在MATLAB中將大型數組直接寫入磁盤時,是否需要預先分配?

[英]When writing a large array directly to disk in MATLAB, is there any need to preallocate?

我需要編寫一個太大的數組,以適應.mat二進制文件的內存。 這可以通過matfile函數來完成,該函數允許隨機訪問磁盤上的.mat文件。

通常,接受的建議是預分配數組,因為在循環的每次迭代中擴展它們都很慢。 但是,當我問如何做到這一點時,我發現在寫入磁盤而不是RAM時這可能不是一個好建議。

數組增長會產生相同的性能影響如果是這樣,那么與寫入磁盤所需的時間相比 ,它會顯着嗎?

(假設整個文件將在一個會話中寫入,因此嚴重文件碎片的風險很低 。)

問:增長陣列會產生相同的性能影響,如果是這樣,那么與寫入磁盤所需的時間相比,它會顯着嗎?

答:是的,如果您在沒有預先分配的情況下顯着增加磁盤上的文件,性能將受到影響。 性能受到影響將是碎片化的結果。 正如您所提到的,如果文件是在一個會話中編寫的,則碎片風險較小,但如果文件顯着增長則會導致問題。

MathWorks網站上提出了一個相關問題 ,接受的答案是盡可能預先分配。

如果您沒有預先分配,那么您的性能問題的程度將取決於:

  • 你的文件系統(數據如何存儲在磁盤上,簇大小),
  • 您的硬件(硬盤尋道時間或SSD訪問時間),
  • mat文件的大小(是否移動到非連續空間),
  • 和存儲的當前狀態(現有碎片/可用空間)。

讓我們假裝您正在運行最近的Windows操作系統,因此使用NTFS文件系統 讓我們進一步假設它已經設置為默認的4 kB簇大小。 因此,磁盤空間以4 kB塊的形式分配,並將這些位置索引到主文件表。 如果文件增長且連續空間不可用,則只有兩種選擇:

  1. 將整個文件重新寫入磁盤的新部分,其中有足夠的可用空間。
  2. 對文件進行分段,將其他數據存儲在磁盤上的不同物理位置。

文件系統選擇執行最不好的選項#2,並更新MFT記錄以指示新群集在磁盤上的位置。

從WindowsITPro上NTFS上的碎片文件的插圖

現在,硬盤需要物理地移動讀頭以便讀取或寫入新簇,這是一個(相對)慢的過程。 在移動磁頭方面,等待磁盤的正確區域在其下面旋轉......你可能正在尋找大約10ms的尋道時間。 因此,每次敲擊碎片時,HDD都會有額外的10ms延遲,以便訪問新數據。 SSD具有更短的尋道時間(沒有移動部件)。 為簡單起見,我們忽略了多盤系統和RAID陣列!

如果你在不同的時間繼續增長文件,那么你可能會遇到很多碎片。 這實際上取決於文件的增長時間/數量,以及您使用硬盤的方式。 您遇到的性能影響還取決於您閱讀文件的頻率以及您遇到片段的頻率。

MATLAB以列主要順序存儲數據,並且從注釋中看起來您有興趣對數據集執行逐列操作(總和,平均值)。 如果列在磁盤上變得不連續,那么你將在每次操作時擊中大量碎片!

如評論中所述,讀取和寫入操作都將通過緩沖區執行。 正如@ user3666197指出的那樣,操作系統可以推測性地預讀磁盤上的當前數據,因為您可能希望接下來的數據。 如果硬盤有時處於空閑狀態 - 保持其以最大容量運行並且在緩沖存儲器中處理小部分數據可以極大地提高讀寫性能,則此行為尤其有用。 但是,從你的問題來看,聽起來好像你想對一個巨大的(太大的內存).mat文件執行大型操作。 鑒於您的用例,硬盤無論如何都將以容量工作,而且數據文件太大而無法容納緩沖區 - 因此這些特殊技巧無法解決您的問題。

所以......是的,你應該預先分配。 是的,在磁盤上增加陣列的性能會受到影響。 是的,它可能會很重要(這取決於具體的增長量,碎片等)。 如果你真的要深入了解HPC的精神,那么就停止你正在做的事情,拋棄MATLAB,破壞你的數據並嘗試類似Apache Spark的東西! 但這是另一個故事。

這是否回答你的問題?

PS更正/修正歡迎! 我是在POSIX inode上長大的,如果這里有任何不准確之處,我真誠地道歉......

在RAM中預先分配變量並在磁盤上預分配不能解決同樣的問題。

在RAM中

為了在RAM中擴展矩陣,MATLAB創建一個具有新大小的新矩陣,並將舊矩陣的值復制到新矩陣中並刪除舊矩陣。 這會花費很多性能。

如果預先分配了矩陣,則其大小不會改變。 所以沒有理由讓MATLAB再次進行矩陣復制。

在硬盤上

GnomeDePlume說,硬盤上的問題是碎片化 即使文件是在一個會話中編寫的,碎片仍然是一個問題。

原因如下:硬盤通常會有點碎片化。 想像

  • #是硬盤上已滿的內存塊
  • M是硬盤上用於保存矩陣數據的內存塊
  • -成為硬盤上的空閑內存塊

現在,在將矩陣寫入其中之前,硬盤可能看起來像這樣:

###--##----#--#---#--------------------##-#---------#---#----#------

當您編寫矩陣的某些部分(例如MMM塊)時,您可以想象這個過程看起來像這樣>!(我舉一個例子,文件系統將從左到右依次使用第一個足夠大的空閑空間 -真實的文件系統是不同的):

  1. 第一個矩陣部分:
    ###--##MMM-#--#---#--------------------##-#---------#---#----#------
  2. 第二個矩陣部分: ###--##MMM-#--#MMM#--------------------##-#---------#---#----#------
  3. 第三個矩陣部分: ###--##MMM-#--#MMM#MMM-----------------##-#---------#---#----#------
  4. 等等 ...

顯然,雖然我們在沒有做任何其他事情的情況下編寫它,但硬盤上的矩陣文件仍然是碎片化的。

如果矩陣文件已預先分配,這可能會更好。 換句話說,我們告訴文件系統我們的文件有多大,或者在這個例子中,我們要為它保留多少內存塊。

想象一下矩陣需要12個塊: MMMMMMMMMMMM 我們通過預先分配告訴文件系統我們需要這么多,它將盡可能地滿足我們的需求。 在這個例子中,我們很幸運:有大於= 12個內存塊的可用空間。

  1. 預分配(我們需要12個內存塊):
    ###--##----#--#---# (------------) --------##-#---------#---#----#------
    文件系統保留矩陣的括號之間的空格並寫入那里。
  2. 第一個矩陣部分:
    ###--##----#--#---# (MMM---------) --------##-#---------#---#----#------
  3. 第二個矩陣部分:
    ###--##----#--#---# (MMMMMM------) --------##-#---------#---#----#------
  4. 第三個矩陣部分:
    ###--##----#--#---# (MMMMMMMMM---) --------##-#---------#---#----#------
  5. 矩陣的第四部分和最后部分:
    ###--##----#--#---# (MMMMMMMMMMMM) --------##-#---------#---#----#------

Voilá,沒有碎片!


比喻

一般來說,您可以將此過程想象為購買大型團體的電影票。 你想團結在一起,但是劇院里已經有一些座位由其他人保留。 為了使收銀員能夠滿足您的要求(大型團隊想要團結在一起),他/她需要了解您的團隊有多大(預分配)。

快速回答整個討論(如果您沒有時間關注或技術理解):

  • Matlab中的預分配與RAM中的操作相關。 Matlab不提供對I / O操作的低級訪問,因此我們不能談論在磁盤上預先分配內容。
  • 在向磁盤寫入大量數據時,已經發現寫入次數越少,執行任務越快,磁盤碎片越少。

因此,如果您不能一次寫入, 請將寫入分成大塊

序幕

這個答案基於作者在最近一周提供的原始帖子和澄清 (兩者)。

由文件系統和文件訪問層引入的低級,物理媒體相關的“碎片”引入的不良性能影響問題在TimeDOMAIN幅度和ComputingDOMAIN重復性中進一步面臨其中這種方法的實際問題

最后提出了針對給定任務的最先進的, 主要是最快的可能解決方案 ,以便最大限度地減少浪費的努力和錯誤解釋錯誤對理想化或其他無效假設造成的損害,類似於“嚴重文件碎片化”的風險由於一個假設,整個文件將在一個會話中寫入(這在當代O / S的許多多核/多進程操作中實際上在一段時間內實際上是不可能的) -creation和一系列廣泛的修改(參考MATLAB大小限制)在當代COTS文件系統內的TB大小的BLOB文件對象。


人們可能會討厭事實,但事實仍然存在,直到更快更好的方法進入


首先,在考慮性能之前,要實現概念上的差距

  1. 真正的性能不利影響不是由HDD-IO 引起的也不與文件碎片有關

  2. RAM 不是 .mat文件的半永久存儲的替代方案

  3. 額外的操作系統限制和干預 +額外的驅動程序和基於硬件的抽象被忽略了對不可避免的開銷的假設
  4. 所述計算方案從對最終性能的最大影響/影響的評論中省略

鑒於:

  • 整個處理只運行一次 ,沒有優化/迭代,沒有連續處理

  • 數據有1E6 double浮點值x 1E5列=約0.8 TB (+ HDF5開銷)

  • 盡管有原始帖子,但沒有與處理相關的隨機IO

  • 數據采集階段與.NET通信,以將DataELEMENT接收到MATLAB中

    這意味着,從v7.4開始,

    基於32位Win的MATLAB WorkSpace1.6 GB limit (帶3GB交換機的2.7 GB)

    對於wXP / 1.4 GB wV / 1.5 GB中MATLAB最大矩陣1.1 GB limit

    對於32位Linux操作系統中最大的Matrix,MATLAB WorkSpace + 2.3 GB限制有點“釋放” 2.6 GB limit

    具有64位O / S將無法幫助任何類型的32位MATLAB 7.4實現,並且由於另一個限制 (陣列中的最大單元數量) 將無法工作 ,這將不包括此處請求的1E12。

    唯一的機會是兩者都有

  • 數據存儲階段假定行排序數據塊(行排序數據塊的集合)的塊寫入到HDD設備上的MAT-file

  • 數據處理階段假定在獲取所有輸入並將所有輸入編組到基於文件的脫RAM存儲之后,在HDD設備上的MAT-file重新處理數據,但是以列順序的方式

  • 只需按列計算mean() s / max() es需要計算( 不再復雜

事實:

  • MATLAB對二進制文件使用HDF5文件結構的“受限制”實現。

檢查實際數據和真實硬件(HDD + SSD)的性能測量,以獲得其不可避免的弱點的尺度感

分層數據格式( HDF )誕生於1987年的國家超級計算應用中心( NCSA ),大約20年前。 是的,那個老了。 目標是開發一種文件格式,結合靈活性效率來處理極大的數據集。 不知何故HDF文件沒有在主流中使用,因為只有少數幾個行業確實能夠真正利用它的可怕能力或根本不需要它們。

靈活性意味着文件結構帶來一些開銷,如果數組內容沒有變化就不需要使用(你付出成本而不消耗使用它的任何好處),並假設HDF5限制了數據的整體大小它可以包含一些幫助並保存MATLAB方面的問題是不正確的。

MAT-files原則上是好的,因為它們避免了需要將整個文件加載到RAM中以便能夠使用它。

然而, MAT-files不能很好地完成這里定義和澄清的簡單任務。 試圖這樣做只會導致性能不佳和HDD-IO文件碎片(在write-through期間增加幾十毫秒,而在計算期間少於read-ahead )將無濟於事根本就是判斷整體表現不佳的核心原因。


專業的解決方案

而不是將整個龐大的1E12 DataELEMENT集合移動到MATLAB內存代理數據陣列中,而不是僅為下一個即將到來的HDF5 / MAT-file HDD設備IO-s( write-through s和O)序列流安排/ S與硬件 - 設備鏈沖突/次優化預read-ahead s)以便讓所有的巨大工作“只是[已婚]已准備好”進行一些簡單的調用mean() / max() MATLAB功能(將盡力以另一種順序改進每個1E12 DataELEMENT甚至是TWICE - 是的 -在第一個作業處理夢魘完全停止后, 通過所有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中的臨時存儲緩沖,因為它將逐步計算不超過約3 x 1E6 ADD / CMP寄存器的結果,所有這些都具有靜態布局, 避免代理 -存儲到HDF5 / MAT-file絕對避免所有與HDD-IO相關的瓶頸和低BigDATA持續讀取的速度(完全沒有談到臨時/ BigDATA持續寫入...)並且還可以避免不良內存-mapped僅用於計算mean-s和max-es。


結語

太陽下​​的管道處理並不是什么新鮮事。

它重復使用速度導向的HPC解決方案已經使用了幾十年

[BigDATA標簽之前的幾代人已經在營銷部門“發明”了。 ]

忘掉數以萬計的HDD-IO阻塞操作,並進入流水線分布式流程到流程解決方案。


沒有比這更快的了


如果是的話 ,所有外匯業務和HFT對沖基金怪獸都已經存在......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM