オカムはレベルが上がった。YAML::Tinyを覚えた

YAML::Tiny気に入った。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Data::Dumper;
use Devel::Size qw(size total_size);
use FindBin qw($Bin);
use Path::Class qw/dir file/;
use lib dir($Bin, '..', 'lib')->stringify;

use YAML::Tiny;

my $file = file($Bin, '..', 'data', 'item.yml')->stringify;
my $tiny = YAML::Tiny->read($file);

warn size $tiny;
warn Dumper $tiny->[0];

my $yaml = do { local $/; <DATA> };

my $tiny2 = YAML::Tiny->read_string($yaml);

warn size $tiny2;
warn Dumper $tiny2->[0];

__DATA__
item_id:
  1:
    heal_infection:
      perfomance_lebel: 1
  2:
    heal_infection:

ただ中身見るのにblessされた配列、つまりオブジェクトを見に行ってるので何かメソッドを用意したほうがいいような気もしたけど何かしらの意図があるんでしょう。

たぶん。

追記

ベンチ取ってみた。

#!/usr/bin/env perl
use strict;
use warnings;
use FindBin qw($Bin);
use Path::Class qw/dir file/;
use UNIVERSAL::require;
use Benchmark qw(:all);
use Data::Dumper;

my $file = file( $Bin, '..', 'data' , 'sample.yml' )->stringify;

open my $fh, '<', $file or die;
my $yaml = do { local $/; <$fh> };
close $fh;

cmpthese timethese 10_000, {
    'YAML::XS' => sub {
        YAML::XS->require or die $@;
        my $data = YAML::XS::Load($yaml);
    },
    'YAML::Syck' => sub {
        YAML::Syck->require or die $@;
        my $data = YAML::Syck::Load($yaml);
    },
    'YAML::Tiny' => sub {
        YAML::Tiny->require or die $@;
        my $tiny = YAML::Tiny->read($yaml);
    },
};

__END__
:!perl bench/yaml_parser_vs.pl
Benchmark: timing 10000 iterations of YAML::Syck, YAML::Tiny, YAML::XS...
YAML::Syck:  4 wallclock secs ( 0.00 usr +  4.03 sys =  4.03 CPU) @ 2481.39/s (n=10000)
YAML::Tiny: -1 wallclock secs ( 0.22 usr +  0.59 sys =  0.81 CPU) @ 12345.68/s (n=10000)
  YAML::XS:  5 wallclock secs ( 0.67 usr +  3.76 sys =  4.43 CPU) @ 2257.34/s (n=10000)
              Rate   YAML::XS YAML::Syck YAML::Tiny
YAML::XS    2257/s         --        -9%       -82%
YAML::Syck  2481/s        10%         --       -80%
YAML::Tiny 12346/s       447%       398%         --

うーん。てっきりモジュールのロードこみならYAML::Tinyのほうが高速だと思ってましたが、そうじゃないのかな…

このベンチはモジュールのロードを何度も繰り返しているイメージで書いたんですが、一回読んだ後はもうロードしないのかも、

という追跡調査を自分でやると時間かかるので明日他人に聞く

さらに追記

とりあえず上のベンチだと「推測の通りrequireしたら次からはメモリに展開済みなので正確なベンチにならないですね」

とのこと。

うーん。そうするとYAMLのデータ量を増やすと結局XS,Syckのほうが速いだろーなーとか思いこむ。

しらべる。

一度requireされて、すでにシンボルテーブルにいろいろ生えた状態なので純粋にYAMLを読み込み、解析してハッシュ(もしくは配列)へと変更するベンチマークだと思って上記のベンチスクリプトを再実行

:!perl bench/yaml_parser_vs.pl
Benchmark: timing 10000 iterations of YAML::Syck, YAML::Tiny, YAML::XS...
YAML::Syck:  4 wallclock secs ( 0.00 usr +  4.03 sys =  4.03 CPU) @ 2481.39/s (n=10000)
YAML::Tiny: -1 wallclock secs ( 0.22 usr +  0.59 sys =  0.81 CPU) @ 12345.68/s (n=10000)
  YAML::XS:  5 wallclock secs ( 0.67 usr +  3.76 sys =  4.43 CPU) @ 2257.34/s (n=10000)
              Rate   YAML::XS YAML::Syck YAML::Tiny
YAML::XS    2257/s         --        -9%       -82%
YAML::Syck  2481/s        10%         --       -80%
YAML::Tiny 12346/s       447%       398%         --

yamlの量を増やして再計測

:!perl bench/yaml_parser_vs.pl
Benchmark: timing 10000 iterations of YAML::Syck, YAML::Tiny, YAML::XS...
YAML::Syck: 14 wallclock secs ( 0.30 usr + 13.87 sys = 14.17 CPU) @ 705.72/s (n=10000)
YAML::Tiny:  1 wallclock secs ( 0.47 usr +  1.06 sys =  1.53 CPU) @ 6535.95/s (n=10000)
  YAML::XS: 15 wallclock secs ( 1.40 usr + 13.65 sys = 15.05 CPU) @ 664.45/s (n=10000)
             Rate   YAML::XS YAML::Syck YAML::Tiny
YAML::XS    664/s         --        -6%       -90%
YAML::Syck  706/s         6%         --       -89%
YAML::Tiny 6536/s       884%       826%         --

むぅ。。。

YAMLの構造は複雑なものもあって、YAML::Tinyはある程度複雑なものは処理しないようにしてスピードを出してる、とかそんなのかなー?

ちなみにテストコードはここにおいてある

http://github.com/okamuuu/practice/tree/master/YAML-Tiny/