XML::Parser(expat)使ってみたけれど
ベンチの内容は RSS の permalink を取り出すだけのものですが,
XML::LibXML や XML::Simple は一度 XML 木を生成しているのでちょっと無駄っぽい。XML::Parser のストリームタイプ(コールバックスタイル)で扱えば,がんばれば勝てるのではないかと思ってごりごり書いてみました。
15アイテムの RSS ファイルを元にやってみましたが…
Benchmark: timing 100 iterations of XML::LibXML, XML::Parser, XML::RSS, XML::Simple, regexp... XML::LibXML: 1 wallclock secs ( 0.85 usr + 0.01 sys = 0.86 CPU) @ 116.28/s (n=100) XML::Parser: 3 wallclock secs ( 2.84 usr + 0.01 sys = 2.85 CPU) @ 35.09/s (n=100) XML::RSS: 68 wallclock secs (67.63 usr + 0.01 sys = 67.64 CPU) @ 1.48/s (n=100) XML::Simple: 14 wallclock secs (14.18 usr + 0.15 sys = 14.33 CPU) @ 6.98/s (n=100) regexp: 0 wallclock secs ( 0.04 usr + 0.00 sys = 0.04 CPU) @ 2500.00/s (n=100) (warning: too few iterations for a reliable count)
うーん,XML::LibXML には勝てなかったです。なぜか XML::RSS が律速になってるし。ちなみにバージョンは,
です。
ソースはこちら。
簡易ステートマシンを構築する必要があるので,XML::Parser の版だけモジュールにわけました。
package RetrievePermalink; use strict; use XML::Parser; our $ONLY_COUNT_LINES = 0; my $STATE_START = 0; my $STATE_ITEM = 1; my $STATE_LINK = 2; my $state; my @permalinks; my $num_permalinks; my @strings; sub parse { _get_parser()->parse(@_); return $ONLY_COUNT_LINES ? $num_permalinks : @permalinks ; } sub parsefile { _get_parser()->parsefile(@_); return $ONLY_COUNT_LINES ? $num_permalinks : @permalinks ; } sub _get_parser { @permalinks = (); $num_permalinks = 0; $state = $STATE_START; return XML::Parser->new( Handlers => { Start => \&_elem_start, End => \&_elem_end, Char => \&_char, }, ); } sub _elem_start { my ($expat, $element) = @_; return unless $element eq 'item' || $element eq 'link'; if ($element eq 'item') { return unless $state == $STATE_START; $state = $STATE_ITEM; } elsif ($element eq 'link') { return unless $state == $STATE_ITEM; $state = $STATE_LINK; @strings = (); } } sub _elem_end { my ($expat, $element) = @_; return unless $element eq 'item' || $element eq 'link'; if ($element eq 'item') { return unless $state == $STATE_ITEM; $state = $STATE_START; if (@strings) { $num_permalinks ++; if (! $ONLY_COUNT_LINES) { push @permalinks, join('', @strings); } @strings = (); } } elsif ($element eq 'link') { return unless $state == $STATE_LINK; $state = $STATE_ITEM; } } sub _char { my ($expat, $string) = @_; return unless $state == $STATE_LINK; push @strings, $string; } 1;
すんごい巨大な XML ファイルを食わせればメモリ効率の点でも XML::Simple 等に勝てると思いますが調べていません。