Nokogiri构建器在巨大的XML上表现?

时间:2012-03-16 02:35:44

标签: ruby xml nokogiri builder

我需要构建一个大约1-50 MB的巨大XML文件。我认为使用构建器会足够有效,而且有点。问题是,在程序到达最后一行后它不会立即结束,但Ruby仍在做几秒钟的事情,可能是垃圾收集?之后程序终于结束了。

举一个真实的例子,我测量了构建XML文件的时间。在构建XML时,它输出55秒(后面有一个数据库,所以需要很长时间),但Ruby仍然会处理大约15秒钟,处理器就会疯狂。

伪/真实代码如下:

...
builder = Nokogiri::XML::Builder.with(doc) do |xml|
  build_node(xml)
end
...

def build_node(xml)
  ...
  xml["#{namespace}"] if namespace  
  xml.send("#{elem_name}", attrs_hash) do |elem_xml|
  ...
    if has_children
      if type
        case type
          when XML::TextContent::PLAIN
            elem_xml.text text_content
          when XML::TextContent::COMMENT
            elem_xml.comment text_content
          when XML::TextContent::CDATA
            elem_xml.cdata text_content
         end
       else
         build_node(elem_xml)
       end
    end
  end
end

请注意,我使用自己的类结构使用不同的方法,并且构建的速度是相同的,但在最后一行程序通常结束,但现在我被迫使用Nokogiri所以我必须找到解决方案。

在构建XML之后,我可以做些什么来避免X秒长的开销?它甚至可能吗?

更新:

感谢Adiel Mittmann的建议,在创建我的最小工作示例期间,我能够找到问题所在。我现在有一个很小的(很小的)例子来证明这个问题。

以下代码导致问题:

xml.send("#{elem_name}_") do |elem_xml|
  ...
  elem_xml.text text_content #This line is the problem
  ...
end

因此该行根据Nokogiri的文档执行以下代码:

def create_text_node string, &block
  Nokogiri::XML::Text.new string.to_s, self, &block
end
然后

Text node creation code被执行。那么,到底发生了什么?

更新2:

经过其他一些尝试后,可以通过以下方式轻松复制问题:

builder = Nokogiri::XML::Builder.new do |xml|
  0.upto(81900) do
    xml.text "test"
  end
end
puts "End"

真的是Nokogiri本身吗?我有什么选择吗?

2 个答案:

答案 0 :(得分:3)

您的示例在此处执行也需要很长时间。而你是对的:垃圾收集器需要很长时间才能执行。试试这个:

require 'nokogiri'
class A
  def a
    builder = Nokogiri::XML::Builder.new do |xml|
      0.upto(81900) do
        xml.text "test"
      end
    end
  end
end
A.new.a
puts "End1"
GC.start
puts "End2"

此处,延迟发生在"End1""End2"之间。打印"End2"后,程序立即关闭。

请注意,我创建了一个对象来演示它。否则,构建器生成的数据只能在程序完成时进行垃圾回收。

至于做你想要完成的事情的最佳方式,我建议你提出另一个问题,详细说明你正在尝试用XML文件做些什么。

答案 1 :(得分:0)

尝试使用Ruby内置(原文如此)Builder。我也使用它来生成大型XML文件,并且它的占用空间很小。