Rails - 循环卷发请求吃内存

dam*_*ser 5 multithreading curb ruby-on-rails-3

我使用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
Run Code Online (Sandbox Code Playgroud)

似乎Rails不等待得到结果req.perform.

编辑:
尝试过一次只对Curl::Easy对象进行实例化,在调用之后使用Curl::Easy.perform()req.close(应该隐式调用GC)但是没有成功的大内存使用.(我认为)可以解决的唯一解决方案是"阻止"轨道,直到响应出现,但如何?

编辑2
在另一项任务中,我只打电话给a_method_that_do_sub_specifics_call没有问题.

编辑3
经过一些性能模式(放置find_each(:batch_size => ...),GC.start...)后,任务工作得更好一点......现在第一个~100循环(do_a_call)工作正常,之后内存使用率再次从100Mb跳到2Gb +.

dam*_*ser 6

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

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

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

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

@status = "#{@status} Warning - response is empty for #{description}\n"
Run Code Online (Sandbox Code Playgroud)

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

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

Model.find_each(:batch_size => 50) do |row|
Run Code Online (Sandbox Code Playgroud)

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

有用的链接: