splitの高速化

配列代入のコスト - マツモブログ

splitも中で配列を作ってるんじゃなかろうかと思いまして正規表現でパースしたのと比較してみました。

・・・中略・・・

微妙な差ですな。

訂正 2007/06/25


うちの環境では結構差がでました。
ちなみに正規表現を最小マッチにしたらもう気持ち早くなりました。

sub parse_regexp_min_match {
    $_[0] =~ /^(.+?)\t(.+?)\t(.+?)\t(.+)/;
    return ($1, $2, $3, $4);
}
Benchmark: timing 1000 iterations of regexp, regexp_min_match, split...
    regexp:  6 wallclock secs ( 6.86 usr +  0.00 sys =  6.86 CPU) @ 145.77/s (n=1000)
regexp_min_match:  6 wallclock secs ( 6.03 usr +  0.00 sys =  6.03 CPU) @ 165.84/s (n=1000)
     split: 15 wallclock secs (14.21 usr +  0.00 sys = 14.21 CPU) @ 70.37/s (n=1000)
                   Rate            split           regexp regexp_min_match
split            70.4/s               --             -52%             -58%
regexp            146/s             107%               --             -12%
regexp_min_match  166/s             136%              14%               --

コメントで頂いたとおり結果がまるで出鱈目だった為再計測しました。
ついでに第3引数指定した場合のsplitも追加。これはあまり変わりませんでした。
正規表現との比較では普通の正規表現ではsplitの方が高速ですが、最小マッチにすると正規表現が上回りました。
環境はperl5.8.8 Celeron1.80GHzです。

#!/usr/local/bin/perl

use strict;

use Benchmark qw(:all);

chomp (my @list = map { s/ +/\t/g; $_ } <DATA>);
# 運命の5,000王子
my @large_list = (@list) x 1000;

sub parse_split {
    return split "\t", $_[0];
}

sub parse_split_3 {
    return split "\t", $_[0], 4;
}

sub parse_regexp {
    $_[0] =~ /^(.+)\t(.+)\t(.+)\t(.+)/;
    return ( $1, $2, $3, $4);
}

sub parse_regexp_min_match {
    $_[0] =~ /^(.+?)\t(.+?)\t(.+?)\t(.+)/;
    return ( $1, $2, $3, $4);
}

my $res = Benchmark::timethese(1000, {
    "split"  => sub { parse_split($_)  for @large_list },
    "split_3"  => sub { parse_split_3($_)  for @large_list },
    "regexp" => sub { parse_regexp($_) for @large_list },
    "regexp_min_match" => sub { parse_regexp_min_match($_) for @large_list },
});

Benchmark::cmpthese($res);

__DATA__
マリポーサ  メキシコ    100000000   偽マッスルリベンジャー
アタル  キン肉星    1080000 ナパームストレッチ
ビッグボディ    カナダ  100000000   メイプルリーフクラッチ
スーパーフェニックス    オーストラリア  100000000   マッスルリベンジャー
ゼブラ  ナムビア    100000000   マッスルインフェルノ
Benchmark: timing 1000 iterations of regexp, regexp_min_match, split, split_3...
    regexp: 30 wallclock secs (30.02 usr +  0.01 sys = 30.03 CPU) @ 33.30/s (n=1000)
regexp_min_match: 17 wallclock secs (17.14 usr +  0.00 sys = 17.14 CPU) @ 58.34/s (n=1000)
     split: 21 wallclock secs (20.72 usr +  0.00 sys = 20.72 CPU) @ 48.26/s (n=1000)
   split_3: 19 wallclock secs (19.35 usr +  0.00 sys = 19.35 CPU) @ 51.68/s (n=1000)
                   Rate       regexp         split      split_3 regexp_min_match
regexp           33.3/s           --          -31%         -36%             -43%
split            48.3/s          45%            --          -7%             -17%
split_3          51.7/s          55%            7%           --             -11%
regexp_min_match 58.3/s          75%           21%          13%               --