配列代入のコスト
調べものをしていたら配列の作成は結構コストを食うようだというのに気付きました。
ベンチとってみたので晒してみます。
サンプルデータは例によってキン肉マン。
#!/usr/local/bin/perl use strict; use Benchmark qw(:all); my @list = <DATA>; # 運命の5,000王子 my @large_list = (@list) x 1000; sub parse1 { return split "\t", $_[0]; } sub parse2 { my $line = shift; return split "\t", $line; } sub parse3 { my $line = shift; my @line = split "\t", $line; return @line; } my $res = Benchmark::timethese(100, { "1.直接返す" => sub { parse1($_) for @large_list }, "2.引数を受ける" => sub { parse2($_) for @large_list }, "3.引数/Arrayを受ける" => sub { parse3($_) for @large_list }, }); Benchmark::cmpthese($res); __DATA__ マリポーサ メキシコ 100000000 偽マッスルリベンジャー アタル キン肉星 1080000 ナパームストレッチ ビッグボディ カナダ 100000000 メイプルリーフクラッチ スーパーフェニックス オーストラリア 100000000 マッスルリベンジャー ゼブラ ナムビア 100000000 マッスルインフェルノ
Benchmark: timing 1000 iterations of 1.直接返す, 2.引数を受ける, 3.引数/Arrayを受ける... 1.直接返す: 24 wallclock secs (23.91 usr + 0.00 sys = 23.91 CPU) @ 41.82/s (n=1000) 2.引数を受ける: 25 wallclock secs (25.05 usr + 0.00 sys = 25.05 CPU) @ 39.92/s (n=1000) 3.引数/Arrayを受ける: 38 wallclock secs (37.15 usr + 0.00 sys = 37.15 CPU) @ 26.92/s (n=1000) Rate 3.引数/Arrayを受ける 2.引数を受ける 1.直接返す 3.引数/Arrayを受ける 26.9/s -- -33% -36% 2.引数を受ける 39.9/s 48% -- -5% 1.直接返す 41.8/s 55% 5% --
リストに1回受ける(配列を作成する)だけで1.5倍強速度に差が出ました。
(引数受ける受けないはあんまり変わらないですね。)
で、更に
splitも中で配列を作ってるんじゃなかろうかと思いまして正規表現でパースしたのと比較してみました。
#!/usr/local/bin/perl use strict; use Benchmark qw(:all); my @list = <DATA>; # 運命の5,000王子 my @large_list = (@list) x 1000; sub parse_split { return split "\t", $_[0]; } sub parse_regexp { $_[0] =~ /^(.+)\t(.+)\t(.+)\t(.+)/; return ($1, $2, $3, $4); } my $res = Benchmark::timethese(1000, { "split" => sub { parse_split($_) for @large_list }, "regexp" => sub { parse_regexp($_) for @large_list }, }); Benchmark::cmpthese($res); __DATA__ マリポーサ メキシコ 100000000 偽マッスルリベンジャー アタル キン肉星 1080000 ナパームストレッチ ビッグボディ カナダ 100000000 メイプルリーフクラッチ スーパーフェニックス オーストラリア 100000000 マッスルリベンジャー ゼブラ ナムビア 100000000 マッスルインフェルノ
Benchmark: timing 1000 iterations of regexp, split... regexp: 19 wallclock secs (19.81 usr + 0.00 sys = 19.81 CPU) @ 50.48/s (n=1000) split: 23 wallclock secs (22.53 usr + 0.00 sys = 22.53 CPU) @ 44.39/s (n=1000) Rate split regexp split 44.4/s -- -12% regexp 50.5/s 14% --
微妙な差ですな。
しかしながら
ウン百万件あるログのパース処理とかには少し気を使えば書き方一つで結構なチューニングが出来そうです。