読者です 読者をやめる 読者になる 読者になる

Perl日記

PerlとかRubyとかPHPとかPythonとか

ループの外で宣言すると早くなる?

ループをたくさん回す処理を高速化する初歩の初歩。 - このブログは証明できない。
こちらを見て少し気になったのでPerlベンチマークやってみた。

#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw/ timethese cmpthese /;

my $out_of_loop = sub {
  my $i; # 外に出す
  for $i ( 1 .. 100 ) {
    1;
  }
};
my $with_loop = sub {
  for my $i ( 1 .. 100 ) { # 都度エイリアス
    1;
  }
};

cmpthese(
  timethese(
    300_000,
    {
      out_of_loop => $out_of_loop,
      with_loop   => $with_loop,
    },
  )
);

なんかすごくばらつきがある。

Benchmark: timing 300000 iterations of out_of_loop, with_loop...
out_of_loop:  3 wallclock secs ( 2.36 usr +  0.00 sys =  2.36 CPU) @ 127118.64/s (n=300000)
 with_loop:  2 wallclock secs ( 1.84 usr +  0.00 sys =  1.84 CPU) @ 163043.48/s (n=300000)
                Rate out_of_loop   with_loop
out_of_loop 127119/s          --        -22%
with_loop   163043/s         28%          --
Benchmark: timing 300000 iterations of out_of_loop, with_loop...
out_of_loop:  3 wallclock secs ( 2.74 usr +  0.00 sys =  2.74 CPU) @ 109489.05/s (n=300000)
 with_loop:  2 wallclock secs ( 1.83 usr +  0.01 sys =  1.84 CPU) @ 163043.48/s (n=300000)
                Rate out_of_loop   with_loop
out_of_loop 109489/s          --        -33%
with_loop   163043/s         49%          --
Benchmark: timing 300000 iterations of out_of_loop, with_loop...
out_of_loop:  3 wallclock secs ( 2.73 usr + -0.01 sys =  2.72 CPU) @ 110294.12/s (n=300000)
 with_loop:  2 wallclock secs ( 1.81 usr +  0.00 sys =  1.81 CPU) @ 165745.86/s (n=300000)
                Rate out_of_loop   with_loop
out_of_loop 110294/s          --        -33%
with_loop   165746/s         50%          --

あと、これはPerl5.12.2でやってみたのだけれど、メジャーバージョンでも違いが多少あった。


とりあえず10回やってみた平均。

  • Perl5.12.2
    • out_of_loop .... 113408/s -- -22%
    • with_loop .... 146227/s 29% --
  • Perl5.10.1
    • out_of_loop .... 118985/s -- -24%
    • with_loop .... 155899/s 31% --
  • Perl5.8.9
    • out_of_loop .... 128596/s -- -17%
    • with_loop .... 155534/s 20% --


微妙に違うけど、共通しているのは、

for my $i ( 1 .. 100 ) {

の方が早いということ。
Perlエイリアスだからか、元記事とは違う結果になったなー。


ついでにずっと気になっていたこともやってみた。
if と for の順番で、コンパイラが最適化してくれるのかどうか。

#!/usr/bin/env perl
use strict;
use warnings;
use Benchmark qw/ cmpthese timethese /;

my $out_of_for = sub {
  if (1) { # if を先
    for my $i ( 1 .. 100 ) {
      1;
    }
  }
};
my $in_for = sub {
  for my $i ( 1 .. 100 ) { # for を先
    if (1) {
      1;
    }
  }
};

cmpthese(
  timethese(
    300_000,
    {
      out_of => $out_of_for,
      in => $in_for,
    },
  )
);

10回やってみた平均。

  • Perl5.12.2
    • in .... 117657/s -- -25%
    • out_of .... 157853/s 34% --
  • Perl5.10.1
    • in .... 116288/s -- -18%
    • out_of .... 142633/s 27% --
  • Perl5.8.9
    • in .... 119665/s -- -22%
    • out_of .... 153101/s 28% --


やっぱりループの外に条件文は置いたほうがいいのか…。
たとえ定数でTRUEであっても。
この辺りがインタプリタってことかな。