Ruby:从大文件中的任意点开始读取

2024-01-12

我有一些日志文件想要筛选。内容正是您在日志文件中所期望的:许多单行逗号分隔的文本。每个文件大约有 4 GB。 File.each_line 或 foreach 其中之一大约需要 20 分钟。

由于简单的 foreach 看起来......简单(而且慢),我认为如果我只能告诉它们从哪里开始,两个单独的线程可能能够在同一个文件上工作。但基于我(有限的)知识,我无法决定这是否可能。

有没有办法从任意行开始读取文件?


为了了解一次读取整个文件与逐行读取整个文件有何不同,我对一个大约 99MB、超过 1,000,000 行的文件进行了测试。

greg-mbp-wireless:Desktop greg$ wc filelist.txt 
 1003002 1657573 99392863 filelist.txt

我将以下循环放入 ruby​​ 文件中,并使用 time 命令从命令行运行它:

IO.read(ARGV.first).lines { |l|
}

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 

real    0m1.411s
user    0m0.653s
sys     0m0.169s

然后我将其更改为逐行读取并计时:

IO.readlines(ARGV.first) { |l|
}

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 

real    0m1.053s
user    0m0.741s
sys     0m0.278s

我不知道为什么,但是逐行阅读会更快。这可能与内存分配有关,因为在第一个示例中 Ruby 尝试将整个文件加载到 RAM 中,或者可能这是一个异常,因为我只为每个文件做了一次测试。用一个read使用显式文件大小可能会更快,因为 Ruby 会知道需要提前分配多少。

这就是我测试这个所需的全部:

fcontent = ''
File.open(ARGV.first, 'r') do |fi|
  fsize = fi.size
  fcontent = fi.read(fsize)
end
puts fcontent.size

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 
99392863

real    0m0.168s
user    0m0.010s
sys     0m0.156s

看起来知道需要读多少内容会有很大的不同。

添加回字符串缓冲区的循环会导致以下结果:

File.open(ARGV.first, 'r') do |fi|
  fsize = fi.size
  fi.read(fsize).lines { |l| 
  }
end

greg-mbp-wireless:Desktop greg$ time ruby test.rb filelist.txt 

real    0m0.732s
user    0m0.572s
sys     0m0.158s

这仍然是一个进步。

如果您使用队列并从负责读取文件的线程提供队列,然后从处理传入文本的任何进程中消耗队列,那么您可能会看到更高的总体吞吐量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Ruby:从大文件中的任意点开始读取 的相关文章

随机推荐