AsmXml のラッパーライブラリ ruby-asm-xml を作成しました

AsmXml のラッパーライブラリ ruby-asm-xml を作成しました。

http://github.com/keita/ruby-asm-xml/tree/master

rubyforge にはついさっきプロジェクト申請したばかりなので、まだ gem とかはありません。というか手抜き版なので現時点ではとりあえず動くよ、という段階です(確保したメモリも一切解放しないくらいに手抜きです)。C言語はよく分からないので拡張ライブラリを作るのはとっても苦手です。だから徐々にゆっくりとまともにしていこうと思います。誰か勝手に直してくれると嬉しいです。

AsmXmlというのは、XMLパーサの一種です。アセンブリで実装しているのでとっても速いそうです(以下のグラフによれば、expatの10倍程度速い、という感じに思えます)。

AsmXml - Benchmark

しかしXMLの全てに対応しているわけではない上に、読み取り用データのスキーマXMLの形式で定義してやる必要があります。DOMっぽくXML文書をメモリに全て載せちゃうくせに、DOMみたいに便利にデータにアクセスできるわけではないのです。また3GバイトくらいまでのXML文書しか読めないそうです。

というわけで、用途が限定されるというか現実的な使い所がなかなか思いつかないかも知れない AsmXml なのですが、速いのなら ruby からでも使ってみたくなるかも知れないと思い、ラッパーライブラリを作成してみました。「速い」とはいうものの実際どうなのかを確かめるために一応ベンチマークを採ってみました。

require "benchmarkx"

# 約10MBのXML文書
data = File.read("asm-xml-1.0/examples/data/employees-big.xml") 
scheme = File.read("asm-xml-1.0/examples/data/employees-schema.xml")

GC.disable

n = 10
BenchmarkX.bm do |x|
  x.filename = "result.png"
  x.gruff.title = "Parsing speed of 'employees-big.xml'"
  require "asm_xml"
  x.report("AsmXml") { n.times {AsmXml.parse(data, scheme)} }
  require "xml/libxml"
  x.report("libxml") { n.times {XML::Parser.string(data)} }
  require "xmlparser"
  x.report("expat") { n.times {XMLParser.new.parse(data)}}
end

この結果は次のようになりました。

      user     system      total        real
AsmXml  0.290000   0.030000   0.320000 (  0.322450)
libxml  0.120000   0.090000   0.210000 (  0.246470)
expat  2.530000   0.090000   2.620000 (  3.320874)

http://file.dynamic-semantics.com/hatena/20080714-1.png

というわけで10MB程度のXML文書読み込む場合には、なんとlibxmlの性能はAsmXmlと同等であることが分かりました。expat と比べれば十分に速いので AsmXml の速さに関する売り文句に間違いはないのですが、それだけ libxml が優秀なライブラリであるということでしょうか。皆様素直にlibxmlを使いましょう!

ただしメモリ効率の点では多分AsmXmlの圧勝だと思います(ベンチマークスクリプトのnを大きくするとなんとなく分かります)。ただ、メモリを気にしなければならない程大きなXML文書を読み込む場合には、普通SAX使いますよね。だから、なんというか、AsmXmlは使い所が難しいと思います。