August 15, 2006
前に書いた「配列から効率良くプレースホルダを作る」の続編です。。
TMTOWTDI な Perl だけあって、色々面白い解がありますね。
Powered By iwai.ug - [Perl] プレースホルダの作成って、こうすれば速いのか!
あと、もう一つ、
はてなブックマーク - 他人の切抜 / 2006年08月11日
確かに obfuscate ですが、要するに
で、ちなみにこの方法の場合の処理速度は、だいたい末尾を置換するのより少し速いぐらいでした。
もしかして三項演算子というか、条件分岐が入っているぶん遅いのかもと思ったので、仮に「必ず引数が渡ってくる」という前提とした
ところで、前回は
よくよく考えれば、要素数が増えれば増える程この効率に差が出ます (※) ので、たった一回の処理でも差が出る可能性もあります。
むしろ滅多に書き換えないという前提であれば、「より高速なものを採用したほうが良い」のかも知れません。
以下に、仮に要素数が 1,000 個あった場合のベンチマーク結果 (1 秒間の処理回数) を掲載しておきますので、「可読性や保守性」を選ぶのか、「処理速度」を選ぶのか…。
自分で振ったネタながら、ちょっと真剣に考えたほうが良い気がしてきました。。。
TMTOWTDI な Perl だけあって、色々面白い解がありますね。
Powered By iwai.ug - [Perl] プレースホルダの作成って、こうすれば速いのか!
ちなみに自分は、今までこんな感じでした↓
sub placeholder_from_array {
return join(',', ('?') x @_);
}
確かに、配列を作るのに map() を使うより、このほうが倍近く高速になりますね。あと、もう一つ、
はてなブックマーク - 他人の切抜 / 2006年08月11日
よりobfuscatedな解: 「return @_?"?".",?"x$#_:"";」。id:another さんの解をほんの少しだけ見やすくすると
sub placeholder_from_array {
return @_ ? '?' . ',?' x $#_ : '';
}
こんな感じ。確かに obfuscate ですが、要するに
"?," を繋げて末尾を切り落とすのではなくて、"?" の後ろに ",?" を引数の要素数 - 1 個ぶん連続して結合するという方法ですね。で、ちなみにこの方法の場合の処理速度は、だいたい末尾を置換するのより少し速いぐらいでした。
もしかして三項演算子というか、条件分岐が入っているぶん遅いのかもと思ったので、仮に「必ず引数が渡ってくる」という前提とした
sub placeholder_from_array {
return '?' . ',?' x $#_;
}
を試してみたのですが、これでも substr() を使ったものより若干遅いという結果になりました。ところで、前回は
my @a = qw(foo bar baz);を対象にしてベンチマークを取って、
だから、「一回の処理で数万回この処理を通る」とかじゃないなら、可読性や保守性の高い前者を取りますけどねwと書きましたが「要素数が少ないから」という前提があることを忘れていました。
よくよく考えれば、要素数が増えれば増える程この効率に差が出ます (※) ので、たった一回の処理でも差が出る可能性もあります。
むしろ滅多に書き換えないという前提であれば、「より高速なものを採用したほうが良い」のかも知れません。
以下に、仮に要素数が 1,000 個あった場合のベンチマーク結果 (1 秒間の処理回数) を掲載しておきますので、「可読性や保守性」を選ぶのか、「処理速度」を選ぶのか…。
自分で振ったネタながら、ちょっと真剣に考えたほうが良い気がしてきました。。。
テスト実行環境:
マシン: Lenovo ThinkPad X60 (170649J)
OS: Debian GNU/Linux on colinux 2.6.11-co-0.6.4 (on Windows XP Professional SP2)
CPU: Intel Core Duo 1.66GHz
Memory: coLinux 割り当て 128MB, swap 256MB (Main 1.5GB)
Perl: v5.8.8 built for i686-linux
■ 秒間 1774.87 回
sub placeholder_from_array {
return join(',', map('?', @_));
}
■ 秒間 5320.28 回
sub placeholder_from_array {
return join(',', ('?') x @_);
}
■ 秒間 49455.98 回
sub placeholder_from_array {
(my $str = ('?,' x @_)) =~ s/,$//;
return $str;
}
■ 秒間 50050.05 回
sub placeholder_from_array {
return @_ ? '?' . ',?' x $#_ : '';
}
■ 秒間 51020.41 回
sub placeholder_from_array {
chop(my $str = ('?,' x @_));
return $str;
}
■ 秒間 51975.05 回
sub placeholder_from_array {
return substr('?,' x @_, 0, -1);
}
(※) ちなみに、結果的に一番高速な
substr() を使ったやつですが、要素数の量が増えれば増えるほど期待以上の効果が得られなくなり、引数の要素数が 2,000 ぐらいを超えたあたりから chop() 版に逆転されることもわかりました。逆に言えば要素数が少ない程、
chop() のやつより大差が出ます。うーん。要素数の影響を受けにくい
chop() がいいのか、そもそも 2,000 個の要素なんて渡って来るはずがない (or 滅多にない) と判断出来るのであれば、より速い substr() がいいのか。なかなか難しいもんですね。。。