【发布时间】:2016-06-13 14:44:19
【问题描述】:
我最近遇到了在 Ruby 中与大型 CSV 文件交互的问题。我确信显而易见的解决方案是将这些数据托管在数据库中而不是像这样的文件中,但尽管如此,我还是想找到问题的根源。
我正在与之交互的数据并不太大 - 大约 4300 万个数据点。尺寸为 8760x5000。我真的需要读入整个 CSV 文件,以便对其执行一些映射操作,然后将其转储到新文件中。
我都试过了:
CSV.foreach("file") do |row|
master_arr << row
end
和
master_arr = CSV.read("file")
这两个选项都会触发内存分配错误 - 说明分配的内存不足。该错误通常类似于:
C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1798:in `gets': failed to allocate memory (NoMemoryError)
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1798:in `block in shift'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1796:in `loop'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1796:in `shift'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1738:in `each'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1122:in `block in foreach'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1273:in `open'
from C:/RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/csv.rb:1121:in `foreach'
from compilation.rb:23:in `<main>'
我不知道为什么这是一个问题。 CSV 文件大约 600MB,当我查看机器的资源时,RAM 消耗在失败前仅增长了大约 1GB。在此期间,我还有大约 10GB 的可用 RAM。
如果我创建一个相同大小的数组并用随机数据填充它:
arr1 = Array.new(8760){|i| i+0.111111111111}
arr2 = Array.new(5000){arr1}
将其存储在内存中没有问题,但如果尝试将其写入 CSV 文件,我会收到内存分配错误。我浏览了 CSV.rb 文件,但似乎找不到任何会导致这种情况的东西。
奇怪的是这行得通:
for i in 0..4999
CSV.foreach("file") do |row|
master << row
break if master_arr.length > 3000
end
end
但如果我尝试将文件一分为二,这将不起作用:
CSV.foreach("file_1_2") do |row|
master_arr << row
end
CSV.foreach("file_2_2") do |row_1|
master_arr << row_1
end
就像这些对象没有从内存中释放,但我不明白到底发生了什么。就像我说的,我知道这是一个大文件,它不是最佳选择,但这是一次性解决方案,而且我有可用的资源,应该没问题。
【问题讨论】:
-
您使用的是 64 位 Ruby 吗?你确定它只有 1GB?
-
嗯...这很尴尬,但实际上这就是问题所在。我想当我使用 Rails 的打包安装程序时,它带有一个 32 位实例。不敢相信我什至没有想到这一点。
标签: ruby-on-rails ruby csv memory out-of-memory