5

我使用 gem Curb(也尝试过httparty)来执行大量 http 请求,并且效果很好。但是在我的 ( rake) 任务之一(我执行 20k+ 请求)中,我遇到了内存问题(Rails “吃掉”了超过 2GB 的 RAM,直到没有可用内存为止)。

似乎Rails“不等待”响应并在循环中的另一个线程中继续,问题是这样会创建很多没有被垃圾收集器收集的对象(我认为)并且是内存泄漏的原因。

有一种方法可以让 rails 等到响应到来?(我试过sleep但不是一个稳定的解决方案)。

我有一个这样的伪代码:

def the_start
  while start_date <= end_date do                  # ~ 140 loop 
    a_method_that_do_sub_specifics_call
  end
end

def a_method_that_do_sub_specifics_call
    some_data.each do |r|                          # ~ 180 loop
        do_a_call
        #do something with models (update/create entries,...)
    end
end

def do_a_call                                      # called ~ 25k times
    # with the gem Curb version
    req = Curl::Easy.new do |curl| 
       curl.ssl_verify_peer = false
       curl.url = url
       curl.headers['Content-type'] = 'application/json'
    end
    req.perform

    # actual version, with httparty gem
    req = HTTParty.get("#{url}",
        :headers => {'Content-type' => 'application/json'})
end

似乎 Rails 并没有等到req.perform.

编辑:
也尝试只实例化一次Curl::Easy对象,在调用之后使用Curl::Easy.perform()and req.close(应该隐式调用 GC),但没有成功使用大量内存。(我认为)唯一可行的解​​决方案是在响应到来之前“阻塞”导轨,但是如何?

编辑 2
在另一个任务中,我只调用a_method_that_do_sub_specifics_call没有问题的。

编辑 3
在一些性能模块(放置find_each(:batch_size => ...)GC.start...)之后,任务工作得更好了。现在第一个 ~100 循环(do_a_call)工作得很好,之后内存使用量再次从 100Mb 跃升至 2Gb+。

4

2 回答 2

6

经过几天的调试,阅读了大量的论坛和帖子,我找到了解决方案:
一个适度的类变量字符串,它会一直增长直到发生内存泄漏。

我在旅途中获得的一些有用的笔记:

Curb vs HTTParty
在这两个执行 curl 请求的 gem 之间,性能最好的是Curb. http://bibwild.wordpress.com/2012/04/30/ruby-http-performance-shootout-redux/

注意类变量
我的问题是一个继续增长的调试/信息变量字符串类,避免使用垃圾收集器永远不会收集的类变量。在我的具体情况下是:

@status = "#{@status} Warning - response is empty for #{description}\n"

执行一些手动垃圾收集
在关键点 执行一些手动操作GC.start,以确保释放不再需要的内存。请记住,调用GC.start不会对垃圾收集器执行即时调用,它只是建议它。

调用 ActiveRecords 数组
调用大 ActiveRecords 时使用.find_each,例如:

Model.find_each(:batch_size => 50) do |row|

这每次只对 50 行(或小于默认值的行)执行查询,比调用 1k 行的单个查询要好。(我猜默认batch_size是1000)。

有用的链接:

于 2013-04-30T22:04:31.703 回答
0

尝试像池一样使用几个 Curl 实例。您一直在创建一个新对象。

于 2013-04-26T13:14:48.307 回答