2016-06-13 3 views
1

Недавно я столкнулся с проблемой взаимодействия с большими файлами 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 

Это как эти объекты не быть выпущенный из памяти, но я точно не понимаю, что происходит. Как я уже сказал, я знаю, что это большой файл, и это не самый лучший вариант, но это одноразовое решение, и у меня есть доступные ресурсы, в которых это не должно быть проблемой.

+3

Вы используете 64-битный Ruby? Вы уверены, что это всего лишь 1 ГБ? – tadman

+0

Ну ... Это довольно смущающе, но на самом деле это было проблемой. Я предполагаю, что когда я использовал пакетный установщик для Rails, он пришел с 32-битным экземпляром. Не могу поверить, что я даже не подумал об этом. –

ответ

0

Как правило, 32-разрядные программы подвержены гораздо более строгим ограничениям памяти, чем 64-разрядные, а 32-разрядный Ruby не может выделить столько памяти, сколько 64-разрядная версия.

Если вы можете проверить, что ваша установка является правильной версией, а если нет, обновите ее справа. ruby -v обычно сообщает вам, какой из них вы используете.