HEXA BLOG

プログラム

HEXA BLOGプログラム2014.6.3

動的言語PHPのパフォーマンス

WWDCが開催されましたね
いくつか発表がありましたが、個人的には新しい開発言語のSwiftが気になっているドラゴンです

時間ができたら試してみたいですね。

 

今回はPHPというスクリプト言語の話です
今でこそ多くのサーバーサイド向け言語が登場していますが、
その中でもPHPは使用率が一番高い(と思われる)言語です。
学習コストや開発コストが低く、開発経験者も多いのが特徴です

 

ただし、深く考えずにPHPを使用すると多くの地雷を踏みます…
以前のプロジェクトで、数万件以上のデータに関して集計スクリプトを動かしている時に、
確保できるメモリの上限を超えてしまったり、
何時間経っても集計が終了しなかったりと多くの問題が出ました。
それを受けてPHPのパフォーマンスに関して調査してみたので、書いてみたいと思います

 

■引数は参照で渡さなくても良い?

PHPの参考書や解説サイトを見ていると、メソッドに対して参照渡しをしている人は少ないです。
C++から学んだプログラマだと、サイズが大きい変数を渡すことはコピーコストへの懸念があります。
もちろんC#のように言語として参照渡しを基本とする訳でもなく、
メソッド内で変数を書き換えても渡し元には影響がありません。
気になったので計測してみました。

 

function profile($delegate, $arrSize) {
    $times = array();
    $mems = array();

    for ($i = 0; $i < 50; ++$i) {
        $in = range(0, $arrSize - 1);

        $startTime = microtime(true);
        $startMem = memory_get_usage();

        $out = $delegate($in);

        $endTime = microtime(true);
        $endMem = memory_get_usage();

        array_push($times, ($endTime - $startTime) * 1000);
        array_push($mems, ($endMem - $startMem) - 64);

        unset($out);
        unset($startTime);
        unset($startMem);
        unset($endTime);
        unset($endMem);
        unset($in);
    }

    echo "[{$delegate}] time  : " . (array_sum($times) / count($times)) . " ms\n";
    echo "[{$delegate}] memory: " . number_format(array_sum($mems) / count($mems))  . " byte\n";
}

この計測関数で、

 

function test11($in) {
    return $in;
}
function test12(&$in) {
    return $in;
}
function &test13(&$in) {
     return $in;
}

profile('test11', 100000);
profile('test12', 100000);
profile('test13', 100000);

を計測してみると、

 

[test11] time : 0.0040435791015625 ms
[test11] memory: 0 byte
[test12] time : 3.7040662765503 ms
[test12] memory: 5,324,376 byte
[test13] time : 0.0040054321289062 ms
[test13] memory: 0 byte

 

コピーコストがかかっていない…だと…!?
そして参照で引数を渡し、値渡しで戻り値を受け取っているtest12はそれっぽくコストがかかっていますね。
test11の結果には疑問が出ましたが、それ以外は予想通りです。

 

この結果を受けて調べてみたところ、どうも変数に対して何らかの書き込みが入った時に
コピーされる仕様になっているようです。
計測してみました。

 

function test21($in) {
    $in[0] = 0;
    return $in;
}
function test22(&$in) {
    $in[0] = 0;
    return $in;
}
function &test23(&$in) {
    $in[0] = 0;
    return $in;
}

profile('test21', $arr);
profile('test22', $arr);
profile('test23', $arr);

[test21] time : 3.6681509017944 ms

[test21] memory: 5,324,409 byte
[test22] time : 3.6571836471558 ms
[test22] memory: 5,324,377 byte
[test23] time : 0.0046634674072266 ms
[test23] memory: 0 byte

 

そういうことか…!
動的言語は凄いですね。
基本的には参照を使用しないことで書き換えによる危険性に備え、
更に無駄なコピーもかからない仕様になっています。
念の為、readのみに関しても計測してみました。

 

function test31($in) {
    count($in);
    return $in;
}
function test32(&$in) {
    count($in);
    return $in;
}
function &test33(&$in) {
    count($in);
    return $in;
}

profile('test31', $arr);
profile('test32', $arr);
profile('test33', $arr);

[test31] time : 0.004730224609375 ms

[test31] memory: 0 byte
[test32] time : 9.3855237960815 ms
[test32] memory: 5,324,377 byte
[test33] time : 6.3674116134644 ms
[test33] memory: 0 byte

 

やはりコピーによるコストはかかっていませんね。
PHPにおいては値渡しを使用する事のメリットは大きそうです。
もちろんtest21の事があるので、何も考えずに値渡しをするのは危険です。

 

 

今回は動的言語であるPHPについて調べてみましたが、
静的言語にはパフォーマンスや堅牢性という良さがあり、
動的言語には開発コストを抑えられるという良さがあります
(しかしPHPにも型安全があればなぁ…

 

言語は適材適所なので、開発言語を選定する場合は色々な方面から考えて、
一番合っていると思われる言語を選べるように色々と試しておきたいですね。

 

ではでは。

RECRUIT

大阪・東京共にスタッフを募集しています。
特にキャリア採用のプログラマー・アーティストに興味がある方は下のボタンをクリックしてください

RECRUIT SITE