Moose is a postmodern object system for Perl 5 that takes the tedium out of writing object-oriented Perl. It borrows all the best features from Perl 6, CLOS (LISP), Smalltalk, Java, BETA, OCaml, Ruby and more, while still keeping true to its Perl 5 roots. It is very powerful and I was curious how fast is in current state. I have read that Moose is slow but all articles what I have found is about two years old. For me is important mostly runtime speed but compile time. So my benchmark is focused only to runtime. I also hate getter/setter combined accessors thus my tests are also only about separated getter and setter. Benchmark code follows.
#!/usr/bin/env perl use strict; use warnings; use Data::Dumper; use Benchmark qw(:all :hireswallclock); { package MooseClassMutable; use Moose; has var => ( is => 'ro', reader => 'get_var', writer => 'set_var', required => 1 ); } { package MooseClassImmutable; use Moose; has var => ( is => 'ro', reader => 'get_var', writer => 'set_var', required => 1 ); no Moose; __PACKAGE__->meta->make_immutable; } { package PerlClass; sub new { my ( $class, %args ) = @_; die 'var value must be set' unless exists $args{var}; return bless \%args, $class; } sub get_var { shift()->{var} } sub set_var { $_[0]->{var} = $_[1] } } { package MooseClassFast; use Moose; with 'MooseX::Emulate::Class::Accessor::Fast'; has var => ( is => 'ro', required => 1 ); __PACKAGE__->follow_best_practice; __PACKAGE__->mk_accessors('var'); no Moose; __PACKAGE__->meta->make_immutable; } cmpthese( -5, { map { my $class = $_; "new $class" => sub { $class->new( var => 1 ) for 1 .. 1000 } } qw(MooseClassMutable MooseClassImmutable PerlClass MooseClassFast) } ); my %objs = ( map { $_ => $_->new( var => 1 ) } qw(MooseClassMutable MooseClassImmutable PerlClass MooseClassFast) ); cmpthese( -5, { map { my $class = $_; my $obj = $objs{$class}; "get $class" => sub { $obj->get_var() for 1 .. 1000 } } qw(MooseClassMutable MooseClassImmutable PerlClass MooseClassFast) } ); cmpthese( -5, { map { my $class = $_; my $obj = $objs{$class}; "set $class" => sub { $obj->set_var(1) for 1 .. 1000 } } qw(MooseClassMutable MooseClassImmutable PerlClass MooseClassFast) } );
I have tested Moose versions 0.54 and 0.68 and just for curiosity also Class::Accessor::Fast
emulation which works only with Moose version 0.68. Notice that rate is measured in thousands. Moose 0.54 results comes first.
Rate new MooseClassMutable new MooseClassImmutable new PerlClass new MooseClassMutable 6.85/s -- -96% -98% new MooseClassImmutable 192/s 2697% -- -53% new PerlClass 403/s 5790% 111% -- Rate get MooseClassMutable get MooseClassImmutable get PerlClass get MooseClassMutable 1716/s -- -2% -25% get MooseClassImmutable 1754/s 2% -- -23% get PerlClass 2273/s 32% 30% -- Rate set MooseClassImmutable set MooseClassMutable set PerlClass set MooseClassImmutable 1611/s -- -2% -16% set MooseClassMutable 1643/s 2% -- -14% set PerlClass 1916/s 19% 17% --
Moose version 0.68 follows.
Rate new MooseClassMutable new MooseClassFast new MooseClassImmutable new PerlClass new MooseClassMutable 15.4/s -- -84% -92% -96% new MooseClassFast 98.7/s 541% -- -48% -76% new MooseClassImmutable 190/s 1138% 93% -- -54% new PerlClass 412/s 2579% 318% 116% -- Rate get MooseClassFast get MooseClassImmutable get MooseClassMutable get PerlClass get MooseClassFast 1716/s -- -2% -2% -24% get MooseClassImmutable 1743/s 2% -- -1% -23% get MooseClassMutable 1754/s 2% 1% -- -22% get PerlClass 2261/s 32% 30% 29% -- Rate set MooseClassFast set MooseClassMutable set MooseClassImmutable set PerlClass set MooseClassFast 78.6/s -- -95% -95% -96% set MooseClassMutable 1659/s 2011% -- -1% -15% set MooseClassImmutable 1680/s 2038% 1% -- -14% set PerlClass 1950/s 2381% 18% 16% --
Moose seems fast enough for me. If I realize how powerful Moose is results are great. I can persist class definition using make_immutable
in most of cases and 190 thousand object constructions per second is enough. There is also big improvement in mutable version between 0.54 and 0.68 and 15 thousand per second is not terrible. Moose accessors are really fast and make_immutable
have not any impact here. 1.7 million reads and 1.6 million writes per second is enough and my ugly handcrafted accessors can't make big difference here (2.2Mr/s and 1.9Mw/s). There is strange Class::Accessor:Fast setter result and I'm curious why. Anyway Moose itself performs well and there is not reason using it.
2 comments:
Moose inlines all accessors by default, so make_immutable is irrelevant. Your benchmark does make that quite clear.
Sorry to double post but ...
You may not realize this, but MooseX::Emulate::Class::Accessor::Fast just uses Moose under the hood, so its accessor should be identical to regular Moose. It's useful if you have a module already using Class::Accessor::Fast (CAF) which you'd like to convert over to Moose.
It was written for Catalyst 5.80, which will be Moose-based. I think the goal is to allow plugins which use the CAF API to work with the new Catamoose.
Post a Comment