tokuhirom's Blog

given-when を dispatcher としてつかう場合の注意事項

せっかく given-when 構文をつかえるのだから、以下のように Dispatcher を書けばいいのではないか、という話があったので実際つかってみていたのだが、このような書き方は非常に低速であることがわかった(too slow)。

use 5.010;
sub dispatch {
    my ($class, $c) = @_;
    given ([$c->request->method, $c->request->path_info]) {
        when (['GET', '/']) {
            return call("Root", 'index');
        }
        ...
    }
}

以下のようなベンチマークスクリプトをうごかすと 25倍遅い。

use strict;
use warnings;
use Benchmark qw/:all/;
use 5.010;

my $method = "GET";
my $path   = "/";
if (@ARGV) {
    $method = 'POST';
    $path   = '/entry';
}

print $],$/;
cmpthese(
    -1, {
        'given-when' => \&given_when,
        'if-else'    => \&if_else,
    },
);

sub if_else {
    if ($method eq 'GET' && $path eq '/') {
        return 'root';
    } elsif ($method eq 'GET' && $path eq '/history') {
        return 'history';
    } elsif ($method eq 'POST' && $path eq '/entry') {
        return 'add_entry';
    } else {
        return '404';
    }
}

sub given_when {
    given ([$method, $path]) {
        when (['GET', '/']) {
            return "root";
        }
        when (['GET', '/history']) {
            return "history";
        }
        when (['POST', '/entry']) {
            return "add_entry";
        }
        default {
            return '404';
        }
    }
}
5.010001
                Rate given-when    if-else
given-when   84329/s         --       -96%
if-else    2323548/s      2655%         --