2010-08-18 96 views
6

我有一個非常大的二進制文件集,其中幾千個原始視頻幀正在順序讀取和處理,我現在正在尋找優化它,因爲它似乎是更CPU的約束比I/O限制。.NET二進制文件讀取性能

目前正在讀這樣的框架,我懷疑這是最大的罪魁禍首:

private byte[] frameBuf; 
BinaryReader binRead = new BinaryReader(FS); 

// Initialize a new buffer of sizeof(frame) 
frameBuf = new byte[VARIABLE_BUFFER_SIZE]; 
//Read sizeof(frame) bytes from the file 
frameBuf = binRead.ReadBytes(VARIABLE_BUFFER_SIZE); 

難道多大的差別在.NET重新組織的I/O,以避免用每一幀創建所有這些新的字節數組?

我對.NET的內存分配機制的理解很薄弱,因爲我來自純C/C++背景。我的想法是重新寫這個來共享一個靜態緩衝類,它包含一個非常大的共享緩衝區,其中包含一個整數來跟蹤幀的實際大小,但我喜歡當前實現的簡單性和可讀性,並且寧願保留它CLR已經以某種我不知道的方式處理這個問題。

任何輸入,將不勝感激。

+5

您是否運行了一個分析器來確保性能命中並不來自其他來源?還是你剛剛去了,假設「這可能是它」? – 2010-08-18 19:11:12

+0

嗨大衛, 我跑了幾次性能分析器,這種方法是我最昂貴的一個。因此,我期待看看這個「新的字節[]」方法在.NET中是否是一個明顯的性能殺手。作爲一名C程序員,這看起來與每個緩衝區的數千個「malloc」語句類似,肯定會比重用緩衝區慢。 – rnd 2010-08-18 20:16:59

回答

7

如果您使用binRead.ReadBytes,則不需要初始化frameBuf - 您將返回一個新的字節數組,它將覆蓋剛創建的字節數組。儘管如此,這確實會爲每次讀取創建一個新數組。

如果你想避免創建一堆字節數組,你可以使用binRead.Read,這將把字節放到你提供給它的數組中。但是,如果其他線程正在使用該陣列,他們會看到它的內容正好在它們的前面。確保您可以保證在重新使用之前完成緩衝區。

+0

感謝您指出 - 我相信我的冗餘分配會顯着降低這一點。靜態共享數組正是我正在考慮的內容,但如果性能增益與創建字節數組相比並不大,那麼我寧願堅持使用優雅的解決方案來處理與您概述的相同的複雜問題(共享訪問) 。 – rnd 2010-08-18 20:21:00

1

你需要小心這裏。在這樣的代碼上獲得完全虛假的測試結果是非常容易的,這種結果在實際使用中從不復制。問題在於文件系統緩存,它會緩存從文件中讀取的數據。當您重複運行測試,調整代碼並尋找改進時,麻煩就開始了。

第二次,隨後您運行測試,數據不再脫離磁盤。它仍然存在於緩存中,它只需要一個從內存到內存的拷貝就可以將它放到你的程序中。這非常快,大約需要幾微秒的開銷和複製所需的時間。它以總線速度運行,現代機器至少每秒5千兆字節。

現在,您的測試將顯示您花費大量時間分配緩衝區並處理數據,相對於讀取數據所花費的時間。

這在實際使用中很少再現。數據將不會在緩存中,現在流氓磁盤驅動器需要查找數據(很多毫秒),需要從磁盤上讀取數據(每秒幾十兆字節)。現在讀取數據需要四個時間長度中的三個。如果你設法讓處理步驟快兩倍,你的程序實際上只會運行速度提高0.05%。給或拿。

+0

這是一個很好的觀點,但是我正在對數據集運行我的測試,這個測試數據集將我的機器內存壓縮了幾個千兆字節。我擔心的是,舊C++庫中的類似代碼將在不到一半的時間內處理這個數據集。但是,我注意到這個配置文件警告說每個/ s大約有2,826個頁面正在寫入磁盤,並且該應用程序可能會受到內存限制。我沒有明確地處理這些數組 - 這些可以在GC取消分配之前緩存嗎? – rnd 2010-08-18 20:46:00

+2

這些緩衝區可能很大,大於85KB。哪些讓他們分配在蕙。他們會在那裏停留一段時間,它需要一個第2代收藏。沒有任何東西是免費的,當它們很大時重用緩衝區也是.NET的一個好策略。 – 2010-08-18 20:51:43

+0

如果您想強制文件從磁盤加載,請清除Windows文件緩存,如以下問題所示:http://stackoverflow.com/q/478340/80525 – BKewl 2014-02-05 20:10:31