General

定数が速いか、スタティック変数が速いか

2009年11月21日

現在、view::compile()メソッドは、次のように記述されている。

    static public function compile($source) {
        static $search=array(
            '/(\r\n|\r|\n)(?:\t)([^<%]|<[^%]||%[^>])/',
            '/(\r\n|\r|\n?)<%([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)%>/',
            '/(\r\n|\r|\n?)<%([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\(([\s\S]*?)\)%>/');
        static $replace=array('self','compile_cb');
        // Actually, JIT is just a preg_replace_callback.
        $compiled=preg_replace_callback($search,$replace,$source);
        $code=create_function('$data','?>'.$compiled.'<?php return true;');
        if (!is_callable($code)) return error::compile_error($source,$compiled);
        return $code;
    }


ローカル変数$search,$replaceをスタティックに設定しているのは、同じ内容の変数を何回も定義しなおすのが遅いと思ったから。

でもこれ、本当なの?スタティック変数じゃなく定数を使ったら?…など疑問に思ったので、実験してみた。本来はPHPのソースコードをじっくり眺めて解決すればよいのだろうけれど、それも面倒なので、とにかく実験。

実験に使ったソース。
<?php

function test1($text){
    static $test='/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/';
    return preg_replace($test,$test,$text);
}

define('_TEST','/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/');
function test2($text){
    return preg_replace(_TEST,_TEST,$text);
}

$text='sdnvrf[sdc;werqwpefdsvad';
$t1a=$t2a=0;
for($i=0;$j<20;$j++){
    $tc=get_msec();
    for($i=0;$i<1000;$i++) $text2=false;
    $tc=get_msec()-$tc;
    $t1=get_msec();
    for($i=0;$i<1000;$i++) $text2=test1($text);
    $t1=get_msec()-$t1-$tc;
    $t2=get_msec();
    for($i=0;$i<1000;$i++) $text2=test2($text);
    $t2=get_msec()-$t2-$tc;
    echo substr($t1,0,5), $t1<$t2?' < ':' > ', substr($t2,0,5), ' ', substr(abs($t1-$t2),0,5), "\n";
    $t1a+=$t1;
    $t2a+=$t2;
}

echo "\n";
$t1=$t1a/20;
$t2=$t2a/20;
echo substr($t1,0,5), $t1<$t2?' < ':' > ', substr($t2,0,5), ' ', substr(abs($t1-$t2),0,5), "\n";

function get_msec(){
    $t=explode(' ',microtime());
    return ($t[0]+$t[1])*1000;
}

実験結果(PHP 5.2.5.5を使用)
5.544 > 5.002 0.541
5.500 > 5.216 0.284
4.776 > 4.677 0.098
4.527 > 4.363 0.164
4.653 > 4.421 0.231
4.604 > 4.495 0.108
4.712 > 4.517 0.195
5.213 > 4.660 0.552
4.455 > 4.375 0.079
4.636 < 4.676 0.040
4.713 > 4.600 0.113
4.637 > 4.567 0.069
5.439 > 5.179 0.260
5.497 > 4.406 1.090
4.771 > 4.661 0.109
4.618 > 4.410 0.208
4.717 > 4.468 0.248
4.780 > 4.428 0.351
4.623 > 4.583 0.040
4.694 > 4.522 0.171

4.855 > 4.611 0.244

結果として、定数を使ったほうが平均で0.2マイクロ秒ほど早い。ちなみに、PHP 5.3.0.0を使った結果もほぼ同じだった。定数が使える場合は、そちらの方が若干速い。

なら、文字列の直書きではどうか。
function test1($text){
    return preg_replace('/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/',
        '/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/',$text);
}

define('_TEST','/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/');
function test2($text){
    return preg_replace(_TEST,_TEST,$text);
}

結果(平均のみ表示)
4.305 < 4.559 0.254

直書きの方が早かった。直書きするよりスタティック変数を使ったほうが速いのではないかと思っていたからそれを多用していたが、それが間違いであることが判明。

では、ローカル変数をスタティック指定する意味はあったのかというと。
function test1($text){
    $test='/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/';
    return preg_replace($test,$test,$text);
}

function test2($text){
    static $test='/sdfwersdfcnwer139r2WEHDFqwr3rASFADSF/';
    return preg_replace($test,$test,$text);
}

結果
5.802 > 5.234 0.567
6.070 > 5.839 0.230
4.562 < 4.573 0.010
4.829 < 5.054 0.224
4.836 > 4.823 0.012
4.614 < 4.672 0.058
4.694 > 4.685 0.009
4.631 < 4.645 0.013
4.623 < 4.824 0.201
4.720 > 4.680 0.040
5.002 > 4.933 0.069
4.660 < 4.678 0.018
4.760 > 4.719 0.040
4.526 < 4.551 0.025
4.738 > 4.645 0.092
4.500 < 4.623 0.122
4.646 < 4.700 0.053
5.519 > 4.614 0.904
4.493 < 4.602 0.108
5.523 > 5.429 0.093

4.887 > 4.826 0.061

ほとんど同じ……。

実験して分かったのは、この辺の工夫はスピードには余り影響せず、ソースをきれいにする以外の意味はあまりないこと。スピードを考えるのであれば、定数や変数を定義せずに、直接文字列を与えたほうが速いということが分かった。覚えておこう。

でもね、もし変数に入れておく場合(配列は定数で定義できない)、やっぱりスタティックに定義するだろうなぁ。ソースを眺めた場合、その関数が呼び出されるたびに変数が定義しなおされるのは、どう考えても無駄だし。

定数を使う場合や、変数に文字列を代入するだけの場合、PHP内部では、JITによりメモリ上に構築された文字列へのポインタを与えるだけなんだろう、多分。文字列の演算を行う場合のみ、そのコピーが作成されるということか。

<%media(20091125-jeans0563.zip|ver 0.5.63)%>

コメント

コメントはありません

コメント送信