2011-05-10 67 views
7

我有一個簡單的文本文件,大約150MB。我的代碼將讀取每一行,如果它匹配某些正則表達式,它將被寫入輸出文件。 但是現在,它只是需要很長的時間通過所有的文件做線(幾分鐘)的迭代像用Ruby解析大文件的最快方法

File.open(filename).each do |line| 
    # do some stuff 
end 

我知道它的通過是該文件的行循環需要一段時間,因爲即使我對「#某些東西」中的數據什麼都不做,仍然需要很長時間。

我知道一些unix程序可以像這樣幾乎立即解析大文件(如grep),所以我想知道爲什麼ruby(MRI 1.9)花費這麼長時間來讀取文件,並且有一些方法可以使它更快?

+0

你有沒有考慮過使用'sed'? – 2011-05-10 20:29:37

+0

@奧斯汀我想在純紅寶石中做到這一點 – 2011-05-10 20:47:53

+1

我不能重現這一點。通過150MB文件迭代在這裏需要一秒鐘。肯定比grep慢,但不是你描述的程度。該文件可能有很長的路線?在這種情況下,通過大塊而不是線條閱讀可能會有所幫助(如果完全可以用你想做的事情來做)。 – sepp2k 2011-05-10 20:52:04

回答

3
File.readlines.each do |line| 
    #do stuff with each line 
end 

將讀取整個文件到行的一個數組。它應該快得多,但它需要更多的內存。

+2

[基準測試顯示'readlines'沒有使用大型文件的'foreach'快(http:// stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad)。它也不可擴展。使用'foreach'而不是'readlines',代碼將保持不變,只能縮放,並且讀取的文件越大,運行速度越快。 – 2015-07-31 17:07:17

4

grep相比並不公平,因爲這是一個高度調整的實用程序,它只掃描數據,它不存儲任何數據。當您使用Ruby讀取該文件時,您最終會爲每行分配內存,然後在垃圾回收週期中釋放它。 grep是一個非常精簡且意味着正則表達式處理機器。

您可能會發現,您可以通過使用像grep外部程序使用system或通過管道設施被稱爲達到你想要的速度:

`grep ABC bigfile`.split(/\n/).each do |line| 
    # ... (called on each matching line) ... 
end 
+0

,但是特別讓Ruby比較像grep讀取文件的行速度非常緩慢。假設Ruby絕對不會在這些行上進行處理,只需讀取它們並退出即可。 – 2011-05-10 20:48:56

+3

Ruby必須爲每一行分配內存,然後銷燬內存,這涉及到更多的工作,而不僅僅是像'grep'那樣掃描一個小的滑動緩衝區。 – tadman 2011-05-10 20:53:40

-2

你應該讀入內存,然後解析。當然,這取決於你在找什麼。不要指望從紅寶石奇蹟的表現,尤其是相比其正在爲過去30年;-)優化的C/C++程序

+0

與我概述的代碼有什麼不同? – 2011-05-10 20:50:31

+0

你的代碼依賴於Ruby tokenizer來讀取文件並在每行之後產生控制,然後讀取下一行然後再次產生,等等。我的建議是在內存中讀入一個完整的文件(比如說一個字符串或char數組)你需要的信息。 – Zepplock 2011-05-10 21:02:32

+0

看起來你試圖淹沒c/C++性能,糟糕的嘗試循環只是循環 - 所有其他重要時刻已經在上面覆蓋 – 2014-03-24 12:26:15