【问题标题】:Fastest Way to Parse a Large File in Ruby在 Ruby 中解析大文件的最快方法
【发布时间】:2011-05-11 04:52:46
【问题描述】:

我有一个大约 150mb 的简单文本文件。我的代码将读取每一行,如果它匹配某些正则表达式,它将被写入输出文件。 但是现在,像

一样遍历文件的所有行(几分钟)只需要很长时间
File.open(filename).each do |line|
  # do some stuff
end

我知道循环文件的行需要一段时间,因为即使我对“#do some stuff”中的数据什么都不做,它仍然需要很长时间。

我知道一些 unix 程序几乎可以立即解析像这样的大文件(如 grep),所以我想知道为什么 ruby​​ (MRI 1.9) 需要这么长时间来读取文件,有什么方法可以让它更快?

【问题讨论】:

  • 你考虑过使用sed吗?
  • @Austin 我想用纯红宝石做这个
  • 我无法重现这个。在这里迭代一个 150mb 的文件需要不到一秒钟的时间。当然比 grep 慢,但不是你所描述的程度。该文件是否可能有很长的行?在这种情况下,按块而不是行读取可能会有所帮助(如果您尝试做的事情完全可能的话)。
  • @sepp2k 每行约 300 个字符,您的测试文件中的行有多长?
  • @Henry:在我的测试中,每行长度为 149 个字符,后跟一个换行符(所以我在一百万行中每行有 150 个字符)。

标签: ruby


【解决方案1】:

grep 相比并不公平,因为这是一个高度优化的实用程序,它只扫描数据,不存储任何数据。当您使用 Ruby 读取该文件时,您最终会为每一行分配内存,然后在垃圾回收周期中释放它。 grep 是一个非常精简和平均的正则表达式处理机器。

您可能会发现可以通过使用外部程序(如使用system 调用的grep 或通过管道设施)来达到您想要的速度:

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

【讨论】:

  • 但是与 grep 相比,Ruby 读取文件行的​​速度特别慢。假设 Ruby 对这些行完全不做任何处理,只是读取它们并退出。
  • Ruby 必须为每一行分配内存,然后销毁该内存,这确实比像grep 那样扫描一个小的滑动缓冲区要多得多。
【解决方案2】:
File.readlines.each do |line|
  #do stuff with each line
end

将整个文件读入一个行数组。它应该会快很多,但会占用更多内存。

【讨论】:

【解决方案3】:

你应该把它读入内存然后解析。当然,这取决于你在寻找什么。不要指望 ruby​​ 有奇迹般的性能,尤其是与过去 30 年来一直在优化的 c/c++ 程序相比 ;-)

【讨论】:

  • 您的代码依赖 Ruby 分词器在每行之后读取文件并让出控制权,然后读取下一行然后再次让出,等等。我的建议是将完整的文件读入(比如说一个字符串或char 数组)在内存中提取你需要的信息。
  • 看起来你试图泛滥 c/c++ 性能,糟糕的尝试 - 循环只是循环 - 所有其他重要时刻已经在上面介绍了
  • 不要将文件读入内存。它不可扩展,也没有性能提升。 stackoverflow.com/questions/25189262/why-is-slurping-a-file-bad
猜你喜欢
  • 2011-06-30
  • 1970-01-01
  • 1970-01-01
  • 2015-03-27
  • 2011-03-04
  • 2015-08-06
  • 2019-10-20
  • 2013-01-17
  • 1970-01-01
相关资源
最近更新 更多