3

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

由于一个简单的 foreach 看起来......简单(而且很慢),我想如果我只能告诉他们从哪里开始,两个单独的线程可能能够处理同一个文件。但是根据我的(有限的)知识,我无法决定这是否可能。

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

4

4 回答 4

3

为了查看一次读取整个文件与逐行读取的差异,我测试了一个大约 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具有显式文件大小的 a 可能会更快,因为 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

这仍然是一种改进。

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

于 2010-11-05T04:15:52.060 回答
2

如果您想从文件中的特定行开始,我建议您只使用尾部。

excerpt = `tail -m +5000 filename.log`

这将为您提供从第 5000 行到文件末尾的 filename.log 的内容。

于 2010-11-09T17:32:42.877 回答
1

对于行,可能有点困难,但您可以在文件中查找某个字节。

IO#seek (link)IO#pos (link)都允许您查找文件中的给定字节。

于 2010-11-05T03:05:52.053 回答
0

如果您还没有尝试 faster_csv 并且如果那仍然太慢,请使用像这样在 c 中具有本机扩展的东西 - http://github.com/wwood/excelsior

于 2010-11-05T05:41:43.820 回答