Class::Structのベンチマーク
Class::Structの速度とかメモリ効率とかをちょっと調べてみた.比較対象はClass::Accessor.
Class::Structはstruct関数で配列のリファレンスを渡すと配列をblessし,ハッシュならハッシュをblessする.
package ClassPerson; use base qw(Class::Accessor); ClassPerson->mk_accessors(qw(name age salary)); package StructArrayPerson; use Class::Struct; struct(StructArrayPerson => [name => '$', age => '$', salary => '$']); package StructHashPerson; use Class::Struct; struct(StructHashPerson => {name => '$', age => '$', salary => '$'}); package main; use Benchmark qw(:all); use Devel::Size qw(size total_size); sub mkobj1 { return ClassPerson->new({name => "John", age => 20, salary => 200000}); } sub mkobj2 { return StructArrayPerson->new({name => "John", age => 20, salary => 200000}); } sub mkobj3 { return StructHashPerson->new({name => "John", age => 20, salary => 200000}); } my $obj1 = mkobj1; my $obj2 = mkobj2; my $obj3 = mkobj3; sub getobj1 { return $obj1->name; } sub getobj2 { return $obj2->name; } sub getobj3 { return $obj3->name; } sub setobj1 { $obj1->name("Mike"); } sub setobj2 { $obj2->name("Mike"); } sub setobj3 { $obj3->name("Mike"); } print "constructor\n"; cmpthese(100000, {"Class::Accessor" => \&mkobj1, "Class::Struct(Array)" => \&mkobj2, "Class::Struct(Hash)" => \&mkobj3}); print "\ngetter\n"; cmpthese(1000000, {"Class::Accessor" => \&getobj1, "Class::Struct(Array)" => \&getobj2, "Class::Struct(Hash)" => \&getobj3}); print "\nsetter\n"; cmpthese(1000000, {"Class::Accessor" => \&setobj1, "Class::Struct(Array)" => \&setobj2, "Class::Struct(Hash)" => \&setobj3}); print "Class::Accessor: ", total_size($obj1), "\n"; print "Class::Struct(Array): ", total_size($obj2), "\n"; print "Class::Struct(Hash): ", total_size($obj3), "\n";
こんな感じで速度とメモリサイズを比較する.速度の比較にはBenchmark,メモリサイズの比較にはDevel::Sizeを用いた.
で結果は以下の通り.
constructor Rate Class::Struct(Hash) Class::Struct(Array) Class::Accessor Class::Struct(Hash) 55249/s -- -6% -20% Class::Struct(Array) 58824/s 6% -- -15% Class::Accessor 69444/s 26% 18% -- getter Rate Class::Accessor Class::Struct(Hash) Class::Struct(Array) Class::Accessor 234742/s -- -45% -49% Class::Struct(Hash) 423729/s 81% -- -8% Class::Struct(Array) 460829/s 96% 9% -- setter Rate Class::Accessor Class::Struct(Hash) Class::Struct(Array) Class::Accessor 204499/s -- -46% -49% Class::Struct(Hash) 375940/s 84% -- -7% Class::Struct(Array) 404858/s 98% 8% -- Class::Accessor: 232 Class::Struct(Array): 121 Class::Struct(Hash): 278
newするのは遅いのだがsetterとgetterはClass::Structの配列形式のが一番速い.あと,メモリのサイズはやっぱり配列を使っているだけ少なくすんでいる.速度に関してはClass::Accessorはちょっと遅いという話も聞いていて,Class::Accessor::Fastというモジュールもある.でもやはり配列でオブジェクトを生成するとメモリ効率はよくなるという点は変わらないかなと思う.