Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2013/08/07

Enemy of the State?

I've been glad for all the new life breathed into the Perl community starting with 5.10, but, honestly, there has been only one thing I consistently used in the raft of new stuff added: say. I disliked having to write print "$var\n" each time I wanted to print a line with a newline, and say allowed me an easy way to do that without changing the behavior of print.

But I've been trying out state.
state declares a lexically scoped variable, just like my. However, those variables will never be reinitialized, contrary to lexical variables that are reinitialized each time their enclosing block is entered.
That sounds like a winner, doesn't it? But it left me some questions.

I deal with SQL a lot, and so I have queries in my code. Sometimes, big queries. I'm wondering if assigning the SQL query each time is more costly, CPU-wise, than declaring it as a state variable and just holding it in memory.

#!/usr/bin/perl

use feature qw{ say state } ;
use strict ;
use warnings ;
use Benchmark qw{:all} ;
use Carp ;

use lib '/home/jacoby/lib' ;
use DB ;

my $sql = <<SQL;
        SHOW TABLES
SQL

sub outside {
    my $arrayref = db_arrayref( $sql ) ;
    }

sub use_my {
    my $sql = <<SQL;
        SHOW TABLES
SQL
    my $arrayref = db_arrayref( $sql ) ;
    }

sub use_state {
    state $sql = <<SQL;
        SHOW TABLES
SQL
    my $arrayref = db_arrayref( $sql ) ;
    }

timethese(
    10_000 , {
    'outside'   => sub { outside( ) ; } ,
    'use my'    => sub { use_my( ) ; } ,
    'use state' => sub { use_state( ) ; } ,
    } ) ;

DB.pm is my wrapper for the very complex DBI module, which gives me just three functions: db_do, db_hashref and db_arrayref. DB has %prepared, such that $prepared{ $sql } = $dbh->prepare( $sql ), so that, when using a query over and over again, a pre-prepared statement handle object is passed out.
Benchmark: timing 10000 iterations of outside, use my, use state...
   outside: 476 wallclock secs (14.66 usr +  8.21 sys = 22.87 CPU) @ 437.25/s (n=10000)
    use my: 475 wallclock secs (14.87 usr +  8.01 sys = 22.88 CPU) @ 437.06/s (n=10000)
 use state: 469 wallclock secs (14.68 usr +  8.14 sys = 22.82 CPU) @ 438.21/s (n=10000)
Looks like, in this case, it doesn't make a whole lot of difference. Still, good to know, right?