Perl覚え書き20041208
というわけでベンチマークをしてみた。ソースは以下の通り。
use Benchmark; @html = (...); # 配列定義は省略 50個 timethese(100000, {'TEST1' => '&test1;', 'TEST2' => '&test2;', }); exit; sub test1 { $ignore = 0; $ignore = 1 if !$ignore and grep !/^(["']).*\1|^[^"']/,@html; } sub test2 { $ignore = 0; foreach $html (@html) { if($html !~ /^(["']).*\1|^[^"']/) { $ignore = 1; last; } } }
まあ配列は適当な物でOK。とりあえずここでは関数の最後で $ignore を表示させると 0 と出る、つまり一度もマッチしない物を設定してみた。結果は次の通り。
Benchmark: timing 100000 iterations of TEST1, TEST2... TEST1: 5 wallclock secs ( 4.77 usr + 0.00 sys = 4.77 CPU) @ 20981.96/s (n=100000) TEST2: 5 wallclock secs ( 5.33 usr + 0.00 sys = 5.33 CPU) @ 18768.77/s (n=100000)
5 wallclock と書いてあるのが実行に掛かった秒数で、後ろの @ の後にある xxxx.xx/s という数値が多い方が速いということになるらしい。1秒間に実行できた回数、ということだろう。この場合は grep の方が1.12倍ほど速い。
続いて配列50個のうち、45個目にマッチする要素を置いて実行してみた結果。
Benchmark: timing 100000 iterations of TEST1, TEST2... TEST1: 5 wallclock secs ( 4.91 usr + 0.00 sys = 4.91 CPU) @ 20383.20/s (n=100000) TEST2: 5 wallclock secs ( 4.91 usr + 0.00 sys = 4.91 CPU) @ 20383.20/s (n=100000)
まあこの結果はちょっとできすぎで…何回か実行した中の一回。つまり、これよりも手前でマッチする要素が出てくる場合は TEST2、要するにループを使った方が速いと言うこと。
要素が50個ってことはないと思うんで20個でテスト。
Benchmark: timing 100000 iterations of TEST1, TEST2... TEST1: 2 wallclock secs ( 1.97 usr + 0.00 sys = 1.97 CPU) @ 50787.20/s (n=100000) TEST2: 2 wallclock secs ( 2.25 usr + 0.00 sys = 2.25 CPU) @ 44444.44/s (n=100000)
一度もマッチしない場合は grep の方が1.14倍速い。続いて18/20個にマッチする要素を配置。
Benchmark: timing 100000 iterations of TEST1, TEST2... TEST1: 2 wallclock secs ( 2.16 usr + 0.00 sys = 2.16 CPU) @ 46382.19/s (n=100000) TEST2: 2 wallclock secs ( 2.14 usr + 0.01 sys = 2.16 CPU) @ 46382.19/s (n=100000)
今度も素晴らしい数値が。何度もテストしただけで数値は加工していない。実際に出てきた物だ。
どちらの場合も、90%の位置で処理速度がほぼ同じと言える数値になる。
一応マッチする要素が90%の所までに有ればループの方が有利ではあるが、恐らくほとんどの場合マッチする要素は出てこないと思う。マッチしなかった場合は grep の方が速いわけで、それを考えるとここはやはり grep を使うべきか。どちらにしても10万回試行してこの差だし、しかも掛かった秒数は同じときてる。最大でも1秒に満たないんだからそんなに変わらないんだろう。
次回は、もっと顕著な差が出る正規表現のベンチマーク…の予定。一応ある程度はテストをしているけど結論はまだ出てないためどうなるか不明。別の話になっている可能性大。
んじゃ。