Недавно я столкнулся с проблемой взаимодействия с большими файлами CSV в Ruby. Я уверен, что очевидное решение состоит в размещении этих данных в базе данных вместо файла, подобного этому, но тем не менее я хотел бы найти корень моей проблемы.Ruby CSV Parsing Memory Allocation
Данные, с которыми я взаимодействую, не слишком велики - около 43 М точек данных. Размеры 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 составляет около 600 МБ, и, когда я просматриваю ресурсы своей машины, потребление ОЗУ растет примерно на 1 ГБ до отказа. За это время у меня все еще есть около 10 ГБ доступной оперативной памяти.
Если я создаю массив того же размера и заполнить его случайными данными:
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? Вы уверены, что это всего лишь 1 ГБ? – tadman
Ну ... Это довольно смущающе, но на самом деле это было проблемой. Я предполагаю, что когда я использовал пакетный установщик для Rails, он пришел с 32-битным экземпляром. Не могу поверить, что я даже не подумал об этом. –