I was curios how closures performs in comparison with objects in Perl. I have tested it on counter as the simplest possible abstraction with state.
use Benchmark qw(cmpthese); sub make_counter { my $counter = shift; return sub { $counter++ }; } package counter; sub new { my ( $class, $counter ) = @_; return bless \$counter, $class; } sub inc { ${ shift() }++ } package main; our $inc = make_counter(1); our $counter = counter->new(1); cmpthese( -5, { closure_make => q{make_counter(1)}, object_make => q{counter->new(1)} } ); cmpthese( -5, { closure => q{$main::inc->()}, method => q{$main::counter->inc()} } );
And results are:
Rate closure_make object_make closure_make 420045/s -- -35% object_make 643969/s 53% -- Rate method closure method 2397172/s -- -35% closure 3697681/s 54% --
Well, it is not simple. Both approaches have their benefits but if you want best performance and want little bit abstraction you should pass closure into your hot loop instead objects. But if you want create closure inside loop, than let you try avoid it or change to object. But you should not need it in hot loop anyway. I'm little bit surprised that closure construction is so expensive in perl. I have known that bless is not cheap operation, but closure?
1 comment:
Closures require capturing values from the lexical pad of in the callstack and creating a new CV object with those values.
Devel::Peek show all the that needs to get constructed.
This is about as much work as creating a new hash and allocating data in it, in terms of the number of memory allocations required, etc.
Personally I wouldn't go either way. If that small difference is really meaningful, then you shouldn't be using Perl (OCaml comes to mind). Use whatever is cleaner =)
Post a Comment