XML::Simple におけるパーサーの実行速度比較

XML::Simple は、どんな XML でも Perl のデータ構造に自動変換してくれるかなり便利なモジュールなのですが、中でツリーを解析したりいろいろやってるせいもあって、速度的にはあまり誉められたものではありません。以前に Perl で XML の処理はどれが速いかベンチ で比較したときには、随分遅いなという印象でした。

ただ、XML::Simple はその中で利用するパーサーを色々切り替えられるようになっています。じゃあそれを切り替えたら少しは速くなるんだろうかと気になってベンチを取ってみました。

XML::Simple は $XML::Simple::PREFERRED_PARSER に任意の SAX パーサーを指定するとそれを使ってパースするようになっています。

  • XML::LibXML::SAX
  • XML::SAX::Expat
  • XML::SAX::ExpatXS
  • XML::Parser

今回はこの4つのパーサーを使ってみました。予想では expat を使うよりも libxml2 を使っている方が、他の場合でも大概速いので XML::LibXML::SAX に分があると思ったのですが結果は以下の通り。

$ perl xmlsimple.pl rss
Benchmark: timing 1000 iterations of XML::LibXML::SAX, XML::Parser, XML::SAX::Expat, XML::SAX::ExpatXS...
XML::LibXML::SAX: 13 wallclock secs (13.59 usr +  0.08 sys = 13.67 CPU) @ 73.15/s (n=1000)
XML::Parser: 12 wallclock secs (11.14 usr +  0.00 sys = 11.14 CPU) @ 89.77/s (n=1000)
XML::SAX::Expat: 35 wallclock secs (35.20 usr +  0.00 sys = 35.20 CPU) @ 28.41/s (n=1000)
XML::SAX::ExpatXS: 14 wallclock secs (13.96 usr +  0.00 sys = 13.96 CPU) @ 71.63/s (n=1000)

予想に反してどれも大差もなし。しかも XML::Parser が一番速かった罠。うーん。libxml2 を使ったとしても SAX のレイヤを被ってる分速度出ないっていうことなのかも。あと、パースした文書を Perl のデータ構造に置き換える処理が支配的で parser の違いによる速度差がそれほど顕著に現れないとかかな。

ということで、XML::Simple のパーサーはあまり切り替えても意味がなさそうです。無難に XML::Parser 使っとけと。

ソースは以下。

#!/usr/local/bin/perl
use strict;
use warnings;
use Benchmark;
use FileHandle;
use XML::Simple;

my $rss_file = shift or die "usage $0 \n";
my $fh = FileHandle->new($rss_file)
    or die "cannot open $rss_file: $!";
local $/; # slurp mode
our $content = $fh->getline;
$fh->close;

Benchmark::timethese(1000, {
    'XML::Parser'       => \&with_xml_parser,
    'XML::LibXML::SAX'  => \&with_xml_libxml_sax,
    'XML::SAX::ExpatXS' => \&with_xml_sax_expatxs,
    'XML::SAX::Expat'   => \&with_xml_sax_expat,
});

sub with_xml_parser {
    $XML::Simple::PREFERRED_PARSER = 'XML::Parser';
    parse();
}

sub with_xml_libxml_sax {
    $XML::Simple::PREFERRED_PARSER = 'XML::LibXML::SAX';
    parse();
}

sub with_xml_sax_expatxs {
    $XML::Simple::PREFERRED_PARSER = 'XML::SAX::ExpatXS';
    parse();
}

sub with_xml_sax_expat {
    $XML::Simple::PREFERRED_PARSER = 'XML::SAX::Expat';
    parse();
}

sub parse {
    XML::Simple->new->XMLin($content);
}