2016年4月10日日曜日

perlの無名配列について

自作の perl スクリプトで、次のようなコードがありました。
sub xxxx {
...
    my @tmp_xxxx = split(" ", <FH>) ;
    return $tmp_xxxx[38] ;
}
これを見ていたら、@tmp_xxxx が無駄に思えてきました。オブジェクト指向言語っぽく、split(" ", <FH>)[38] のように書けないのか?と思ったわけです。
調べてみると、無名配列を使うと、次のように書けることを知りました。
sub xxxx {
...
    return = [split(" ", <FH>)]->[38] ;
}
これいいなと思って、他の似た箇所も全部これのほうが良いかなと、さらに自作スクリプトを眺めてみたら、次のようなコードもありました。
...
    (undef, $p) = split(" ", $k)
...
これを見て、性能面では、どの書き方が良いのか?ということが気になってしまいました。
そこで、ベンチマークで確認しました。
#use strict;
#use warnings;
use Benchmark qw(cmpthese timethese :hireswallclock);

$x = "a b c d e f g h i j k l m n o p" ;

cmpthese(1000000,{
    method1 => sub {
        (undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,undef,undef, my $y)
            = split(" ", $x) ;
    },
    method2 => sub {
        my $y = [split(" ", $x)]->[15] ;
    },
    method3 => sub {
        my @temp = split(" ", $x) ;
        my $y = $temp[15] ;
    },
});
[root@hoge ]# cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core)
[root@hoge ]# rpm -q perl
perl-5.16.3-286.el7.x86_64
[root@hoge ]# perl bench_split16.pl 
            Rate method2 method3 method1
method2 386100/s      --    -11%    -43%
method3 434783/s     13%      --    -36%
method1 680272/s     76%     56%      --
このように、無名配列(method2)が一番遅いという結果になりました。しかしながら、[38] などという場合は、実行頻度も加味して、可読性の観点から、無名配列による書き方を選んだほうが良い場合もあると思います。
なお、興味深いことに、CentOS 6 では順序が入れ替わります。
[root@hoge ~]# cat /etc/redhat-release 
CentOS release 6.7 (Final)
[root@hoge ~]# rpm -q perl
perl-5.10.1-141.el6.x86_64
[root@hoge ~]# perl bench_split16.pl 
            Rate method3 method2 method1
method3 349650/s      --    -19%    -48%
method2 432900/s     24%      --    -35%
method1 671141/s     92%     55%      --
ThinkPad W520 のマルチブート環境にて実行しています。

perl を毛嫌いする人を見かけますが、この記事に書いたような側面(同じことを幾通りにも書ける)からなのだろうか?と思いました。ところが、これこそ perl の面白さと思うのです。私的には。
よーし、今こそ、もっと perl 勉強しよう (活用しよう) っと!

2016-04-14追記
「Effective Perl」を読んでみたら、スライスを使って次のように書けることを知りました。
    method4 => sub {
        my ($y) = (split(" ", $x))[15] ;
    },
ふたたび、ベンチマークしてみると、スライス(method4)が1番速いという結果になりました。
[root@hoge ~]# cat /etc/redhat-release 
CentOS release 6.7 (Final)
[root@hoge ~]# rpm -q perl
perl-5.10.1-141.el6_7.1.x86_64
[root@hoge ~]# perl bench_split16.pl
            Rate method3 method2 method1 method4
method3 255754/s      --    -17%    -46%    -48%
method2 307692/s     20%      --    -34%    -38%
method1 469484/s     84%     53%      --     -5%
method4 495050/s     94%     61%      5%      --
[root@hoge ~]# service cpuspeed start
Enabling ondemand cpu frequency scaling:                   [  OK  ]
[root@hoge ~]# perl bench_split16.pl
            Rate method3 method2 method1 method4
method3 347222/s      --    -19%    -46%    -49%
method2 431034/s     24%      --    -33%    -36%
method1 645161/s     86%     50%      --     -5%
method4 675676/s     95%     57%      5%      --
本題からそれますが、cpuspeed を止めていると Turbo Boost まで効かなくなるようで、パフォーマンス低下するようです。前回のベンチの際は、chkconfig on にしてたんですが、性能下がるかと思って off にしてましたが、逆効果でした。マシンは、ThinkPad W520 (Core i7 2960XM) です。利用シーンによっては、逆手にとって、静音性のために chkconfig cpuspeed off もよいかもしれません。
人気ブログランキングへ にほんブログ村 IT技術ブログへ