我使用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()
和req.close
(应该隐式调用GC),但是没有成功使用大量内存。 (我认为)可以解决的唯一解决方案是“阻止”轨道,直到响应出现,但是如何?
编辑2
在另一项任务中,我只调用a_method_that_do_sub_specifics_call
而没有问题。
编辑3
在一些性能模式(放置find_each(:batch_size => ...)
,GC.start
,...)后,任务工作得更好..现在第一个~100循环(do_a_call
)工作正常,之后是内存使用率再次从100Mb跳到2Gb +。
答案 0 :(得分:6)
经过几天的调试,阅读了大量的论坛和帖子,我找到了解决方案:
一个适度的类变量字符串,它会一直增长,直到发生内存泄漏。
我旅行中获得的一些有用的注释:
限制与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"
执行一些手动垃圾收集
在关键点执行一些手动GC.start
以确保释放不再需要的内存。请记住,调用GC.start
不会对垃圾收集器执行即时调用,它只会建议它。
调用ActiveRecords数组
调用大型ActiveRecords时使用.find_each
,例如:
Model.find_each(:batch_size => 50) do |row|
每次只执行50(或小于默认值)行的查询,比调用1k行的单个查询更好。 (我猜默认batch_size
是1000)。
有用的链接:
答案 1 :(得分:0)
尝试像池一样使用几个Curl实例。您一直在创建一个新对象。