【发布时间】:2011-06-18 07:10:17
【问题描述】:
我正在编写一个导入脚本来处理一个可能有数十万行的文件(日志文件)。使用一种非常简单的方法(如下)占用了足够的时间和内存,我觉得它随时会占用我的 MBP,所以我终止了该过程。
#...
File.open(file, 'r') do |f|
f.each_line do |line|
# do stuff here to line
end
end
这个文件有 642,868 行:
$ wc -l nginx.log /code/src/myimport
642868 ../nginx.log
有谁知道处理此文件中每一行的更有效(内存/cpu)方法?
更新
上面f.each_line 内部的代码只是将正则表达式与该行匹配。如果匹配失败,我将该行添加到 @skipped 数组中。如果它通过,我将匹配格式化为哈希(由匹配的“字段”键入)并将其附加到 @results 数组。
# regex built in `def initialize` (not on each line iteration)
@regex = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) - (.{0})- \[([^\]]+?)\] "(GET|POST|PUT|DELETE) ([^\s]+?) (HTTP\/1\.1)" (\d+) (\d+) "-" "(.*)"/
#... loop lines
match = line.match(@regex)
if match.nil?
@skipped << line
else
@results << convert_to_hash(match)
end
我完全同意这是一个低效的过程。我可以让convert_to_hash 中的代码使用预先计算的 lambda,而不是每次都计算出计算。我想我只是假设问题在于行迭代本身,而不是每行代码。
【问题讨论】:
-
最节省内存的方法是使用
each_line的方式。您可以更快地读取块中的文件,然后使用String#lines来抓取各个行,同时重新加入任何跨过块边界的部分加载的行。不得不将线条分开并重新加入破损的线条。
标签: ruby text-processing