2011-05-10 69 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