在rails应用程序中读取大型csv文件会占用大量内存 - 减少内存消耗的策略?

时间:2014-06-02 19:02:33

标签: ruby-on-rails ruby csv

我有一个rails应用程序,允许用户上传csv文件,并在delayed_job gem的帮助下安排读取多个csv文件。问题是应用程序将其文件中的每个文件读入内存,然后写入数据库。如果只读取1个文件就可以了,但是当读取多个文件时,服务器上的RAM会变满并导致应用程序挂起。

我正在尝试找到解决此问题的方法。

我研究过的一个解决方案是将csv文件分成更小的部分并将它们保存在服务器上,并读取较小的文件。请参阅此link

 example: split -b 40k myfile segment

不是我首选的解决方案。有没有其他方法可以解决这个问题,我不必破坏文件。解决方案必须是ruby代码。

谢谢,

1 个答案:

答案 0 :(得分:6)

您可以使用CSV.foreach只读取CSV文件的块:

 path = Rails.root.join('data/uploads/.../upload.csv') # or, whatever
 CSV.foreach(path) do |row|
   # process row[i] here
 end

如果它在后台作业中运行,您还可以在每个 n 行中调用GC.start


如何运作

CSV.foreach在IO流上运行,如您所见:

def IO.foreach(path, options = Hash.new, &block)
  # ...
  open(path, options) do |csv|
    csv.each(&block)
  end
end

csv.each部分是对IO#each的调用,它逐行读取文件(rb_io_getline_1 invokation)并使读取的行被垃圾回收:

static VALUE
rb_io_each_line(int argc, VALUE *argv, VALUE io)
{
    // ...
    while (!NIL_P(str = rb_io_getline_1(rs, limit, io))) {
        rb_yield(str);
    }
    // ...
}