ループの外で宣言すると早くなる?
ループをたくさん回す処理を高速化する初歩の初歩。 - このブログは証明できない。
こちらを見て少し気になったので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であっても。
この辺りがインタプリタってことかな。