我正在尝试读取5MM的行文件,现在它超出了我在Heroku上占用的大量内存。我的方法有点快,大约每秒200次插入。.我相信它在导入时崩溃了。所以我的计划是分批导入1,000或10,000。我的问题是我怎么知道我在文件的末尾,ruby有一个.eof
方法但有一个File
方法,而且我不确定如何在循环中调用它
def self.import_parts_db(file)
time = Benchmark.measure do
Part.transaction do
parts_db = []
CSV.parse(File.read(file), headers: true) do |row|
row_hash = row.to_hash
part = Part.new(
part_num: row_hash["part_num"],
description: row_hash["description"],
manufacturer: row_hash["manufacturer"],
model: row_hash["model"],
cage_code: row_hash["cage_code"],
nsn: row_hash["nsn"]
)
parts_db << part
end
Part.import parts_db
end
end
puts time
end
一旦使用File.read(file)
了巨大的文件,脚本将占用大量内存(可能过多)。您将整个文件读为1个巨大的字符串,即使CSV
逐行读取它也是如此。
当您使用具有数千行的文件时,它可能会正常工作。不过,您应该使用CSV.foreach。改变
CSV.parse(File.read(file), headers: true) do |row|
至
CSV.foreach(file, headers: true) do |row|
在此示例中,内存使用量从1GB变为0.5MB。
parts_db
变成一个巨大的零件阵列,并一直保持增长,直到CSV文件的末尾。您需要删除交易记录(导入速度会很慢,但所需存储空间不会超过1行)或批量处理CSV。
这是一种可能的方法。我们CSV.parse
再次使用,但仅用于2000行批处理:
def self.import_parts_db(filename)
time = Benchmark.measure do
File.open(filename) do |file|
headers = file.first
file.lazy.each_slice(2000) do |lines|
Part.transaction do
rows = CSV.parse(lines.join, write_headers: true, headers: headers)
parts_db = rows.map do |_row|
Part.new(
part_num: row_hash['part_num'],
description: row_hash['description'],
manufacturer: row_hash['manufacturer'],
model: row_hash['model'],
cage_code: row_hash['cage_code'],
nsn: row_hash['nsn']
)
end
Part.import parts_db
end
end
end
puts time
end
end
先前的答案不应使用过多的内存,但是导入所有内容仍会花费很长时间,对于远程服务器来说可能太多。
使用枚举器的优点是可以轻松跳过批处理,并仅获取所需的批处理。
假设您的导入时间过长,并且在成功完成424000次导入后由于某种原因停止了导入。
您可以替换:
file.lazy.each_slice(2000) do |lines|
经过
file.lazy.drop(424_000).take(300_000).each_slice(2000) do |lines|
跳过前424000条CSV行,然后解析下300000条CSV行。
对于下一次导入,请使用:
file.lazy.drop(424_000+300_000).take(300_000).each_slice(2000) do |lines|
然后 :
file.lazy.drop(424_000+2*300_000).take(300_000).each_slice(2000) do |lines|
...
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句