【发布时间】:2019-09-26 15:18:26
【问题描述】:
我需要编写脚本来解析大型输入数据(30GB)。我需要从标准输入文本中提取所有数字并按顺序输出。
使用示例:
cat text_file_30gb.txt | script
现在我用于解析:
numbers = []
$stdin.each_line do |line|
numbers += line.scan(/\d+/).map(&:to_i)
end
numbers.uniq!.sort!.reverse!
但我尝试将文本从 60MB 文件传递到脚本,它解析了 50 分钟
是加速脚本的方式吗?
UPD。分析结果:
%self total self wait child calls name
95.42 5080.882 4848.293 0.000 232.588 1 IO#each_line
3.33 169.246 169.246 0.000 0.000 378419 String#scan
0.26 15.148 13.443 0.000 1.705 746927 <Class::Time>#now
0.18 9.310 9.310 0.000 0.000 378422 Array#uniq!
0.15 14.446 7.435 0.000 7.011 378423 Array#map
0.14 7.011 7.011 0.000 0.000 8327249 String#to_i
0.10 5.179 5.179 0.000 0.000 378228 Array#sort!
0.03 1.508 1.508 0.000 0.000 339416 String#%
0.03 1.454 1.454 0.000 0.000 509124 Symbol#to_s
0.02 0.993 0.993 0.000 0.000 48488 IO#write
0.02 1.593 0.945 0.000 0.649 742077 Numeric#quo
0.01 0.649 0.649 0.000 0.000 742077 Fixnum#fdiv
0.01 0.619 0.619 0.000 0.000 509124 String#intern
0.01 0.459 0.459 0.000 0.000 315172 Fixnum#to_s
0.01 0.453 0.453 0.000 0.000 746927 Fixnum#+
0.01 0.383 0.383 0.000 0.000 72732 Array#reject
0.01 16.100 0.307 0.000 15.793 96976 *Enumerable#inject
0.00 15.793 0.207 0.000 15.585 150322 *Array#each
...
【问题讨论】:
-
嗯,您可能无法一次将所有 30 GB 的内存都保存在内存中,因此您需要在磁盘上对它们进行排序。此外,如果您不为此使用 ruby(而不是使用 C 或其他东西),它可能会更快。
-
@Adrian 我完全同意你的看法,但我需要在 Ruby 上进行考试:(
-
您尝试过类似
IO.foreach('text_file_30gb.txt').lazy.grep(/\d+/)的方法吗?也可以参考这个可能有帮助:blog.honeybadger.io/… -
如果
numbers.uniq!远小于numbers(即,很多重复),您可以将numbers设为一个集合而不是一个数组。这会减少内存需求,但我怀疑它会加快计算速度。您对文件中数字(不是数字)和唯一数字的数量的粗略估计是多少? -
我认为
numbers += ...占用的太多了,因为它会为每个+=调用分配新数组。但是,请改用<<。这将为现有的数组实例增加价值。我正在根据您当前的示例添加一个快速示例,只需进行一些调整就需要 11 到 12 分钟。
标签: ruby algorithm performance