2009-08-10
馬鹿にできないアクセサのオーバーヘッド
Moose は has でアクセサ定義できるので便利なのですが、アクセサは要はサブルーチンコールなので、パフォーマンス気にして作っているサービスではオーバーヘッドが気になるなぁと思い、ちょっとベンチ取ってみました。
ベンチマーク対象は、Moose で作成したクラスと、Class::Accsessor::Fast で作成したクラスの、アクセサ経由とオブジェクト直でのデータ取得です。ベンチマークコードは以下です。
#!/usr/bin/perl package ClassMoose; use Moose; has 'ro1' => ( is => 'ro', isa => 'Bool', default => 1 ); has 'ro2' => ( is => 'ro', isa => 'Int', default => 1 ); has 'ro3' => ( is => 'ro', isa => 'Str' , default => '1' ); has 'ro4' => ( is => 'ro', isa => 'ArrayRef' , default => sub { [] }); has 'ro5' => ( is => 'ro', isa => 'HashRef' , default => sub { {} }); has 'ro6' => ( is => 'ro', isa => 'CodeRef' , default => sub { sub {1} }); has 'rw1' => ( is => 'rw', isa => 'Bool', default => 1 ); has 'rw2' => ( is => 'rw', isa => 'Int', default => 1 ); has 'rw3' => ( is => 'rw', isa => 'Str' , default => '1' ); has 'rw4' => ( is => 'rw', isa => 'ArrayRef' , default => sub { [] }); has 'rw5' => ( is => 'rw', isa => 'HashRef' , default => sub { {} }); has 'rw6' => ( is => 'rw', isa => 'CodeRef' , default => sub { sub {1} }); no Moose; __PACKAGE__->meta->make_immutable; package ClassCAF; use strict; use warnings; use base 'Class::Accessor::Fast'; __PACKAGE__->mk_accessors(qw/rw1 rw2 rw3 rw4 rw5 rw6/); package main; use strict; use warnings; use Benchmark ':all'; my $m = ClassMoose->new; my $c = ClassCAF->new; no warnings 'void'; cmpthese(timethese(300000, { m_ro => sub { $m->ro1; $m->ro2; $m->ro3; $m->ro4; $m->ro5; $m->ro6; }, m_rw => sub { $m->rw1; $m->rw2; $m->rw3; $m->rw4; $m->rw5; $m->rw6; }, m_direct => sub { $m->{'rw1'}; $m->{'rw2'}; $m->{'rw3'}; $m->{'rw4'}; $m->{'rw5'}; $m->{'rw6'}; }, c_rw => sub { $c->rw1; $c->rw2; $c->rw3; $c->rw4; $c->rw5; $c->rw6; }, c_direct => sub { $c->{'rw1'}; $c->{'rw2'}; $c->{'rw3'}; $c->{'rw4'}; $c->{'rw5'}; $c->{'rw6'}; }, }));
結果は以下です。
Rate m_ro m_rw c_rw m_direct c_direct
m_ro 67265/s -- -0% -17% -82% -87%
m_rw 67416/s 0% -- -17% -82% -87%
c_rw 81301/s 21% 21% -- -78% -85%
m_direct 365854/s 444% 443% 350% -- -32%
c_direct 535714/s 696% 695% 559% 46% --
Moose ではアクセサの ro と rw の差は出ませんでした。アクセサ経由ではやはり、Class::Accessor::Fast ベースのクラスの方が小さい分 1.2 倍高速です。ダイレクトアクセスではやはり、アクセサ経由と雲泥の差ですね。
このベンチマーク結果を見ると、やはりアクセサ経由のデータアクセスは減らした方が良い事が分かります。
アクセサ経由のデータアクセスを減らすひとつの方法として、ひとつ例を挙げるとしたら以下の例があります。
まず、このようなコードがあったとします。
sub no_tmp { warn qq/data is / . $o->data; my $foo = $o->data =~ /blah/ ? 'blah' : 'blah'; my $bar = "blah/" . $o->data; my $baz = "blah/" . $o->data; my $file = "/path/to/" . $o->data; if ( !-r $file ) { warn qq/Couldn't read file $file/; } my $str = substr $o->data, 3; }
凄く単純なことなのですが、これをアクセサから取得したデータをレキシカル変数にコピーして使い回す方法にしてみます。
sub use_tmp { my $data = $o->data; # コピー warn qq/data is $data/; my $foo = $data =~ /blah/ ? 'blah' : 'blah'; my $bar = "blah/$data"; my $baz = "blah/$data"; my $file = "/path/to/$data"; if ( !-r $file ) { warn qq/Couldn't read file $file/; } my $str = substr $data, 3; }
この 2 つのサブルーチンのベンチマーク結果です。この例だと 1.5 倍の高速化ができました。
Rate no_tmp use_tmp
no_tmp 15873/s -- -34%
use_tmp 23923/s 51% --
このように、高度なことをしなくてもパフォーマンスチューニングが可能なポイントというのは結構あります。
コメントを書く
トラックバック - http://d.hatena.ne.jp/Craftworks/20090810/1249885786
リンク元
- 17 http://d.hatena.ne.jp/studio-m/20100612/1276311893
- 17 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=Xkl&q=catalyst+apache+fcgi&btnG=検索&lr=lang_ja
- 16 http://reader.livedoor.com/reader/
- 12 http://d.hatena.ne.jp/tomute/20090721/1248235494
- 12 http://webcache.googleusercontent.com/search?q=cache:vjmK7cxZTLgJ:d.hatena.ne.jp/Craftworks/20090805/1249479565+python+空文字列 チェック&cd=10&hl=ja&ct=clnk&gl=jp
- 10 http://d.hatena.ne.jp/
- 10 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCYQFjAA&url=http://d.hatena.ne.jp/Craftworks/20090810/1249885786&ei=pGaST6znPOXOmAWK-Oj7AQ&usg=AFQjCNHfwsd2nEADRaKX0v4dGS6V3t9Wew&sig2=qONF6waZsxRfaB1IL3YrPA
- 10 https://www.google.co.jp/
- 8 http://d.hatena.ne.jp
- 8 http://hatenatunnel.appspot.com/


