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;
こちらのほうがハッシュっぽいですね(よくわかりませんが)。
配列の添字
配列の添字に正の数と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に伝えることができます。
すべての変数に{}を付けるわけにはいきませんが
役立つときはありそうです。