Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I've been looking at Moose and mostly have been very impressed.

There is a 'but'.

But testing on small scripts (with __PACKAGE__->meta->make_immutable) the performance was terrible. Does anyone with experience of large Moose projects had any problems with it?

Replies are listed 'Best First'.
Re: Moose performance
by Anonymous Monk on Nov 11, 2011 at 12:57 UTC
    Show your code. Show your measurement numbers for performance.
      Show your code. Show your measurement numbers for performance.

      That isn't fair. You know what the issue is and it isn't right to try push it back on the OP to demonstrate the performance overhead of Moose.

      Every time someone is surprised by the overhead of Moose in small short lived programs we seem to reply in the following sequence (where each one is admitted more grudgingly):

      • It is just the startup that is slow. Moose is fine for long lived programs.
      • You can use Mouse if you have to.
      • Moose isn't a good fit for short lived programs.

      Perhaps it would be more honest if we replied in the reverse order.

      --
      John.

      Don't think you understand the question. On small scripts performance is poor so I want to know whether its worth using in a proper project.

      Not sure if the balance between performance and syntactic sugar is worth it.

      Moose

      $cat test_moose.pl package NumberHolder; use Moose; has 'x' => (is => 'rw', isa => 'Int'); has 'y' => (is => 'rw', isa => 'Int'); __PACKAGE__->meta->make_immutable; package Main; my $z = NumberHolder->new(x => 1, y => 2); print "z's x and y = ", $z->x()," ", $z->y(), "\n"; $time perl test_moose.pl z's x and y = 1 2 real 0m1.48s user 0m1.06s sys 0m0.11s

      No Moose

      $cat test_nomoose.pl package NumberRun; sub new { my $class = shift; my %args = @_; my %h = ( x => 0, y => 0); @h{ keys %args} = values %args; return bless \%h; } sub x { my $self = shift; $self->{x} = shift if @_; $self->{x}; } sub y { my $self = shift; $self->{y} = shift if @_; $self->{y}; } 1; package Main; use strict; use warnings; my $z = NumberRun->new(x => 1, y => 2); print "z's x and y = ", $z->x()," ", $z->y(), "\n"; $time perl test_nomoose.pl z's x and y = 1 2 real 0m0.07s user 0m0.01s sys 0m0.01s

        You're testing compile time. First scripts loads Moose and tons of its dependencies. Try to write some more realistic tests. Here's something to start:

        use 5.010; use strict; use warnings; { package M1; use Moose; has x => ( is => 'rw' ); } { package M2; use Moose; has x => ( is => 'rw' ); no Moose; __PACKAGE__->meta->make_immutable; } { package M3; use Moose; has x => ( is => 'rw', isa => 'Int' ); no Moose; __PACKAGE__->meta->make_immutable; } { package NM; sub new { my $class = shift; return bless {@_}, $class; } sub x { my $self = shift; $self->{x} = shift if @_; $self->{x}; } } use Benchmark qw( cmpthese ); cmpthese - 5, { "Moose mutable" => sub { M1->new( x => 1 ) }, "Moose immutable" => sub { M2->new( x => 1 ) }, "Moose with type check" => sub { M3->new( x => 1 ) }, "No Moose" => sub { NM->new( x => 1 ) }, };

        Generally, if you're using Moose, code performance will decrease, but your performance and code quality will increase (though it depends of course).

        So basically you measured startup time. The same without startup time:

        #!/usr/bin/perl use strict; use warnings; package NumberHolder; use Moose; has 'x' => (is => 'rw', isa => 'Int'); has 'y' => (is => 'rw', isa => 'Int'); __PACKAGE__->meta->make_immutable; package NumberRun; sub new { my $class = shift; my %args = @_; my %h = ( "x" => 0, "y" => 0); @h{ keys %args} = values %args; return bless \%h; } sub x { my $self = shift; $self->{x} = shift if @_; $self->{x}; } sub y { my $self = shift; $self->{y} = shift if @_; $self->{y}; } package Main; use Benchmark qw( cmpthese ); sub withMoose { my $z = NumberHolder->new("x" => 1, "y" => 2); my $f= $z->x()+ $z->y(); if ($z->x()>0) { $z->y(5); } } sub traditional { my $z = NumberRun->new("x" => 1, "y" => 2); my $f= $z->x()+ $z->y(); if ($z->x()>0) { $z->y(5); } } my %tests = ( "with Moose" => sub { withMoose }, "traditional" => sub { traditional }, ); cmpthese(-5, \%tests); # prints: Rate with Moose traditional with Moose 49776/s -- -55% traditional 111550/s 124% --

        I eliminated the prints as these take a lot of time themselves. Put them in again and the difference will be 80% instead of 124%.

        Now this represents worst case. The methods are minimalist and the test subs just call the methods a few times. Print, read or write to files or use a database and the difference gets smaller and smaller