我正在生成一个XML文件,以便与另一个系统共享数据。根据我的故障排除,我发现这个过程既缓慢又消耗大量内存(在Heroku上获得大量R14。)
我的Jobs Controller上的索引方法如下所示:
def index
respond_to do |format|
format.xml {@jobs = @user.jobs.includes(job_types: [:job_lines, :job_photos])}
format.json
{
# More code here, this part is not the problem.
}
end
end
我的视图(index.xml.builder)看起来像这样(我删除了一堆字段以保持示例更小):
xml.instruct!
xml.jobs do
@jobs.each do |j|
xml.job do
xml.id j.id
xml.job_number j.job_number
xml.registration j.registration
xml.name j.name
xml.job_types do
j.job_types.each do |t|
xml.job_type do
xml.id t.id
xml.job_id t.job_id
xml.type_number t.type_number
xml.description t.description
xml.job_lines do
t.job_lines.each do |l|
xml.job_line do
xml.id l.id
xml.line_number l.line_number
xml.job_type_id l.job_type_id
xml.line_type l.line_type
xml.type_number l.type_number
xml.description l.description
xml.part_number l.part_number
end # job_line node
end # job_lines.each
end # job_lines node
xml.job_photos do
t.job_photos.each do |p|
xml.job_photo do
xml.id p.id
xml.pcid p.pcid
xml.job_type_id p.job_type_id
xml.image_url p.image.url
end # job_line node
end # job_lines.each
end # job_lines node
end # job_type
end # job_types.each
end # job_types node
end # job node
end # @jobs.each
end # jobs node
生成的XML文件不小(大约100kB)。在Heroku上运行,他们的Scout工具告诉我这个过程通常需要4-6秒才能运行。此外,尽管只运行了1个工作线程,但有4个线程(在Puma中),这部分代码消耗了我所有的内存。在scout中,我可以看到它的“Max Allocations”高达10M,而我的下一个最差方法只有500k的分配。
谁能告诉我我做错了什么?是否有更高效的(在速度和内存使用方面)生成XML的方式?
任何帮助都将不胜感激。
编辑1
我已尝试像这样手动构建XML:
joblist.each do |j|
result << " <job>\n"
result << " <id>" << j.id.to_s << "</id>\n"
result << " <job_number>" << j.job_number.to_s << "</job_number>\n"
# Lots more lines removed
end
这给了我一些改进。我最大的拨款现在是1.8M。我接近Heroku的限制(在24小时内达到512MB限制的最大值500MB)。
我仍然只运行1个带有4个线程的工作者。如果我能够更多地记住内存,那么我可以运行更多的Puma Workers和Threads。
编辑2
我最终必须批量执行此操作(使用偏移和限制)并一次发送5个作业。当我这样做时,内存使用量大幅下降。显然,对控制器的调用越来越多,但每个调用都越来越小。