我有大约六个执行JSON爬行的Sidekiq工作者.根据端点的数据集大小,它们在1分钟到4小时之间完成.特别是,观看长达4小时的长时间,我看到随着时间的推移,内存会略有增加.
这不是问题,直到我想再次安排相同的工作人员工作.内存没有被释放并堆积起来,直到我遇到Linux OOM Killer,摆脱了我的Sidekiq进程.
内存泄漏?我在ObjectSpace中观察了不同对象的数量:
ObjectSpace.each_object.inject(Hash.new(0)) { |count, o| count[o.class] += 1 }
Run Code Online (Sandbox Code Playgroud)
那里没有真正的增加,哈希,数组等的集合保持不变,垃圾收集器一扫而空,并gc.stat[:count]告诉我,垃圾收集器也在工作.
即使在工作人员完成之后,例如我得到[完成]记录并且没有工人正忙,但内存不会被释放.这是什么原因?我可以对此做点什么吗?写一个终结者?
目前唯一的解决方案:重启Sidekiq进程.
我在Ruby 2.0.0上使用Ruby MRI.
对于JSON解析,我使用Yajl,因此是C绑定.我需要它,因为它似乎是唯一能够正确实现流式读写的快速JSON解析器.
对于我的测试,我需要一个控制器,我可以设置自己的参数.使用参数我指的是调用时获得的参数controller.params
{"action"=>"show",
"controller"=>"merchants",
"wine_id"=>"1",
"id"=>"346343"}
Run Code Online (Sandbox Code Playgroud)
问题是,我不知道在这里存在什么正确的存根方式.有三种情况:
controller.request.env['action_dispatch.request.path_parameters']controller.paramscontroller.url_options[:_recall]在所有三个中都存储了相同的信息,但是设置这些值的接口方式是什么?
我从1,000个批次的服务器中获取大约20,000个数据集.每个数据集都是JSON对象.坚持这使得大约350 MB的未压缩明文.
我的内存限制为1GB.因此,我将每个1,000个JSON对象作为数组写入附加模式的原始JSON文件中.
结果是一个包含20个JSON数组的文件,需要进行聚合.无论如何我需要触摸它们,因为我想添加元数据.通常Ruby Yajl Parser可以这样做:
raw_file = File.new(path_to_raw_file, 'r')
json_file = File.new(path_to_json_file, 'w')
datasets = []
parser = Yajl::Parser.new
parser.on_parse_complete = Proc.new { |o| datasets += o }
parser.parse(datasets)
hash = { date: Time.now, datasets: datasets }
Yajl::Encoder.encode(hash, json_file)
Run Code Online (Sandbox Code Playgroud)
这个解决方案的问题在哪里?问题是仍然将整个JSON解析为内存,我必须避免.
基本上我需要的是一个解决方案,它从IO对象解析JSON并同时将它们编码到另一个IO对象.
我假设Yajl提供了这个,但我没有找到方法,它的API也没有给出任何提示,所以我猜不是.是否有支持此功能的JSON Parser库?还有其他解决方案吗?
我能想到的唯一解决方案就是使用这些IO.seek功能.写的所有数据集阵列此起彼伏[...][...][...],每个数组后,我找回到开始并覆盖][有,,有效手动连接的阵列.
我有一个积极的分数列表:
[98.5, 85, 50, 50, 23, 0, 0, 0]
Run Code Online (Sandbox Code Playgroud)
我想为这些分数分配排名:
[1, 2, 3, 3, 4, 5, 5, 5]
Run Code Online (Sandbox Code Playgroud)
当两个连续分数具有相同的值时,它们获得相同的等级.知道如何以功能性方式解决这个问题吗?
(发布在Haskell和Ruby中,因为我认为这两种解决方案都是可行的并且可以移植)
我有两个关系为1-n的课程.像这样:
class Band
include Mongoid::Document
has_many :members
end
class Member
include Mongoid::Document
field :name, type: String
field :joined, type: Date
belongs_to :band
end
Run Code Online (Sandbox Code Playgroud)
现在,当我打电话时,band.members我得到了成员对象.我想要的是,如果我打电话band.members.last来获得加入最后一个的成员.我通过定义基于以下的<=>方法Member和排序来实现这一点joined:
band.members.sort.last
Run Code Online (Sandbox Code Playgroud)
如何将此行为设为默认值?我不想避免额外的排序调用.这是可能的,如果可以,怎么样?