我收到错误:在Ruby中编写了大量文件后打开的文件过多

时间:2011-03-18 10:06:20

标签: ruby-on-rails ruby ubuntu

我有一个生成16000个html页面并将其保存在系统中的脚本。在1013页之后,我收到错误:打开的文件过多。

这是生成文件的Ruby代码

FileUtils.mkdir_p "public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}"
FileUtils.mkdir_p "public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}/#{n/1000}"

html_file = File.new("public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}/#{n/1000}/#{n}.html", "w")
html_file.write(html)
html_file.close

你可以看到我在最后一行关闭文件....

有人知道我在这里做错了什么吗?我有Ubuntu 8.04.4 LTS

非常感谢

编辑:

这是整个剧本

    def self.fetching_directory_page(n=1, letter = nil)
      id = letter == '' ? "" : "/#{letter.upcase}"
      url = "this is a valid url :)"
      agent = WWW::Mechanize.new
      page = agent.get(url)
      html = page.search('div#my_profile_body').to_html

      prefix = id == '' ? 'all' : letter
      FileUtils.mkdir_p "public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}"
      FileUtils.mkdir_p "public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}/#{n/1000}"

      html_file = File.new("public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}/#{n/1000}/#{n}.html", "w")
      html_file.write(html)
      html_file.close

      puts "+ CREATED #{prefix}/#{n/1000}/#{n}.html" 

      new_url = page.parser.xpath("//a[@class='next_page']")[0]['href'] rescue nil

      if new_url.present?
        self.fetching_directory_page(n+1, letter)
      end
    end

它正在获取用户目录的所有用户并保存页面以获取缓存原因。它总共生成16000个文件。

这是ulimit-a的结果

    core file size          (blocks, -c) 0
    data seg size           (kbytes, -d) unlimited
    scheduling priority             (-e) 0
    file size               (blocks, -f) unlimited
    pending signals                 (-i) 24640
    max locked memory       (kbytes, -l) 32
    max memory size         (kbytes, -m) unlimited
    open files                      (-n) 24000
    pipe size            (512 bytes, -p) 8
    POSIX message queues     (bytes, -q) 819200
    real-time priority              (-r) 0
    stack size              (kbytes, -s) 8192
    cpu time               (seconds, -t) unlimited
    max user processes              (-u) 24640
    virtual memory          (kbytes, -v) unlimited
    file locks                      (-x) unlimited

编辑/ etc / security / limits之后我没有收到错误Too many open files但它只是卡住了

lsof -u username会返回一个或多或少600个条目的列表,并且在执行脚本时会更改

4 个答案:

答案 0 :(得分:5)

我不确定这是否是解决问题的最佳方法,但它可能有所帮助:

尝试评论一半代码。如果它仍然有问题,那么注释掉剩下的一半。继续这样做直到问题消失。一旦问题消失,请尝试取消注释一些代码。继续这样做,直到问题恢复。更可能的是,您刚刚取消注释的行与错误有关。这种解决问题的方法有时被称为“二进制印章”。

对于这种特殊情况,您可能希望确保调用fetching_directory_page的任何内容每次都不打开新文件而不关闭它。

答案 1 :(得分:2)

打开文件没有导致问题。这是递归方法。我改变了这一点,事情很有效。

答案 2 :(得分:1)

问题似乎是在操作系统中,而不是在ruby脚本本身。

尝试早期SO问题的this建议:

  

检查当前用户有权打开的文件数:在终端运行中ulimit -a并检查打开文件(-n)行。默认值为1024。

     

要解决此问题,您必须修改以下文件:/etc/security/limits.conf

答案 3 :(得分:1)

这是一个小问题,但Ruby支持使用File.open的块,它会自动关闭打开的文件。将这种形式与Ruby一起使用是不恰当的,而不是像你一样:

html_file = File.new("public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}/#{n/1000}/#{n}.html", "w")
html_file.write(html)
html_file.close

应该是:

File.open("public/users_directory/#{DEFAULT_COUNTRY_CODE}/#{prefix}/#{n/1000}/#{n}.html", "w") do |html_file|
  html_file.print html
end

the docs来自IO.open,继承File.open:

  

没有关联的块,IO.open是:: new的同义词。如果给出了可选代码块,它将作为参数传递给io,并且当块终止时IO对象将自动关闭。在这个例子中,:: open返回块的值。