Tuesday, October 6, 2009

Closure vs. Object in Perl

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?