Learn to Live and Live to Learn

IT(たまにビジネス)に関する記事を読んで、考えて、使ってみたことをまとめる場。

Perlでベンチマーク

Perlではその名もBenchmarkというモジュールを使うと
簡単にベンチマーク=性能比較を行えます。

まずはやってみました。

#!/usr/bin/perl -w
use strict;

use Benchmark qw/timethese cmpthese/;

my $result = timethese( 10000, {
	loop1 => sub{
		my $i = 0;
		while ( $i < 1500 ) {
			$i++;
		}
	},
	loop2 => sub{
		my $i = 0;
		while ( $i < 500 ) {
			$i++;
		}
	}
});

cmpthese $result;

実行結果はこちら。

Benchmark: timing 10000 iterations of loop1, loop2...
     loop1:  1 wallclock secs ( 0.76 usr +  0.00 sys =  0.76 CPU) @ 13157.89/s (n=10000)
     loop2:  0 wallclock secs ( 0.25 usr +  0.00 sys =  0.25 CPU) @ 40000.00/s (n=10000)
            (warning: too few iterations for a reliable count)
↓ここからがcmpthese↓
         Rate loop1 loop2
loop1 13158/s    --  -67%
loop2 40000/s  204%    --


説明させていただきます。
timethese関数

timethse( $count, {
    処理1 => sub {
    },
    処理2 => sub {
    }
});

で複数のコードを$countに指定した回数実行できます。
一つの場合はtimethisです。返り値は各関数=処理の性能情報です。
こんな感じです。

$VAR1 = {
          'loop1' => bless( [
                              1,
                              '0.74',
                              0,
                              0,
                              0,
                              10000
                            ], 'Benchmark' ),
          'loop2' => bless( [
                              0,
                              '0.25',
                              0,
                              0,
                              0,
                              10000
                            ], 'Benchmark' )
        };

timetheseで処理は指定回実行されるのですが
その結果を比較したいときはcmptheseを利用します。
cmptheseはtimetheseの結果を比較表で出力します。

comthese $timethese_result;

この書き方とこの書き方どっちが速いの?!というのを
知りたいとき手軽に使用できていいですね(^^)


参考URL
http://d.hatena.ne.jp/perlcodesample/20100509/1276960096
http://www2u.biglobe.ne.jp/MAS/perl/waza/bench.html
http://perldoc.jp/docs/modules/Benchmark-1.10/Benchmark.pod

mapを使って配列からハッシュを作成

「バタバタしていて…」と心の中でできない社会人の典型な言い訳している内に
ブログの最終更新日から10日も経っていました。反省します。

今日、知ったこと

map関数を使うと配列からハッシュを作れる。

例えば配列の要素をキーにして、バリューには1を入れたいときは

%hash = map{ $_, 1 } @array;

mapで配列の要素を一つずつ取り出して、キー, バリューの形で返します。

一応ハッシュができていることを確認しました。

$ perl -e 'my @array = qw/aaa bbb ccc/; my %hash = map{ $_, 1 } @array; foreach my $key ( keys( %hash ) ) { print $key . " => " . $hash{$key} . "\n"; }'
bbb => 1
aaa => 1
ccc => 1

こういう書き方もできるみたいです。

my %hash = map{ @_ => 1 } @array;

こちらのほうがハッシュっぽいですね(よくわかりませんが)。

参考:http://hirobanex.net/article/2011/04/1302036133

配列の添字

配列の添字に正の数と0以外を設定した場合の挙動を調べてみました。

  • 負の値を添字に指定すると、添字の中で最大のものを-1に割り当てて、絶対値が大きくなるに連れて配列を逆向き(末尾から先頭)に見ていきます。

例、
要素数3である@fredを使用。
$fred[-1] = $fred[2]
$fred[-2] = $fred[1]
$fred[-3] = $fred[0]

  • 添字の中にアンスコ(_)を書くとアンスコは無視されます。

例、$fred[1_2]は$fred[12]。


上記を確かめるために利用したスクリプトはこちら。
実際はuse strict;を指定してmyとか付けたほうが良いと思います。

#!/usr/bin/perl -w

$fred[0] = "yabba";
$fred[1] = "dabba";
$fred[2] = "doo";

$length = @fred;

print "Array is\n";
for ( $i = 0; $i < $length; $i++ ) {
	print $fred[$i] . "\n";
}

print "\n";

print "\$fred[-1] is\n";
print $fred[-1] . "\n\n";

print "\$fred[-2] is\n";
print $fred[-2] . "\n\n";

print "\$fred[-3.456] = \$fred[-3] is\n";
print $fred[-3.456] . "\n\n";

print "\$fred[1_2] = \$fred[12] is\n";
print $fred[1_2] . "\n";

実行結果

$ perl list.pl 
Array is
yabba
dabba
doo

$fred[-1] is
doo

$fred[-2] is
dabba

$fred[-3.456] = $fred[-3] is
yabba

$fred[1_2] = $fred[12] is
Use of uninitialized value $fred[12] in concatenation (.) or string at list.pl line 27.

$

おまけ
そもそもリストと配列の違いって普段あまり意識しないのですが
(と言いますか私は≒だと思ってました…)

リストは順序付けされたデータのこと。
配列はそのデータ=リストを格納する変数。

と定義されています。

変数名を明示的に書く方法

変数名は、意味をなす限り、できるだけ長くなるように解釈されます。
(初めてのPerl P40)

Perlでは、変数名に英数字またはアンスコを続けると
それも変数名だと解釈されます。

#!/usr/bin/perl
use strict;
use warnings;
my $what = "brontosaurus steak";
my $n = 3;
print "fred ate $n $whats.\n";
# -> Global symbol "$whats" requires explicit package name at var.pl line 6.
#    Execution of var.pl aborted due to compilation errors.

この場合はまだエラーが出るのでおかしいことに気付けますが

my $whats = "fred";
print "fred ate $n $whats.\n";
# -> fred ate 3 fred.

その変数=$whatsも存在した日には
出力結果はまったくの別物です。
解決策としては

print "fred ate $n ${what}s.\n";
# -> fred ate 3 brontosaurus steaks.

{}を使えばここが変数名ですよーとPerlに伝えることができます。
すべての変数に{}を付けるわけにはいきませんが
役立つときはありそうです。