PHPで性能を無視して書いたプログラムをどうにか高速化しようというのがあって(切実な問題?)、いろいろ調べてみようと思い立った男がいたとして下さい。やっていることは、文字列処理が多いと思う。どう書いたら速くなるのか。
いろいろ調べようと思っているが、まずは少しやってみてわかったことを書く。
文字列の連結についてはいくつかの方法がある。ぱっと思いつくものでも以下の4つである。
- .=演算子(
$var.=val
) - .演算子(
$var=$var.val
) - “”の展開(
$var="{$var}val"
) - sprintf(
$var=sprintf("%sval", $var)
) - join(
$var=join("", array($var, val))
)
このうち、1.の.=が一番速いということがわかった。試行を10万回繰り返して平均を取ると、一回の演算にかかるコストは「$var.=val
」が約2.6us、「$var=$var.val
」は約40us、「$var="{$var}val"
」が約42us、「$var=join("", array($var, val))
」が約44us、「$var=sprintf("%sval", $var)
」が約82usだった。つまり「.=」が圧倒的に速い。sprintfが遅いのは当然としても、それ以外のやつも全部オブジェクトを生成してしまうような感じだ。「.」でつなげるのと「””」で展開していくのはほとんどコストが変わらない。ただし高速化したいのなら「.=」をいくつも書いてつなげたほうがよいということがわかる。
では文字列はどう表現したら速いのか。「”(ダブルクオート)」よりも「'(シングルクオート)」が高速なのは想像できるが、変数に入れて使い回すと速くなったりするのだろうか?
結論を言うと、”と’の差は3〜4%程度までである(“は何も展開されない場合)。10万回のループを何度か試行してみると、ときどき”のほうが’よりも若干高速になることすらあるので、”と’の違いは誤差の範囲であろう。しかし、変数に文字列を入れて参照すると、10%ほど遅くなる。これは常にそうだった。
$b=$a;
$c=$a;
よりも
$b=”{$a}”;
$c=”{$a}”;
は40〜50%遅くなる。まあこれはいいだろう。しかし、
$b=”test”;
$c=”test”;
にすると最初のものよりも10%高速になるのである。ただしこれは1回の演算につき1us程度の部分なので、最適化という点でこの10%を利用するのは無理があると思う。変数を手動で展開すれば1回走るごとに約0.1us速くなる、と覚えよう。ループの中なら意外と変わるかもしれない。展開してメンテナンスがやりにくくなるよりは最初の、文字列の連結の実験でわかったように、生成されるオブジェクトの数を減らすように書き方を工夫するのがよいだろう。
こういう傾向はPHPのバージョンによるのかもしれない。みなさんも実験してみてほしい。私が試しているバージョンはLinux(Kernel 2.4.x)のPHP-4.2.2(Red Hat Linux 8.0のphp-4.2.2-8.0.8)である。
テストプログラムはtest2.php(文字列連結)、test3.php(文字列代入)に置いておく。test2.php、test3.phpとして保存して、
bash# php test2.php | awk '{a[$1]+=$2;b[$1]++;}END{for(i in a){if(b[i]!=0 & a[i]!=0){print i, a[i],a[i]/b[i],a[i]/b[i]/10000;}}}' | sort -n +1
などのように実行するとよいだろうと思う。