さくらインターネットでPHPのstats拡張モジュールを利用可能にする で利用できるようにしたstats拡張モジュールの関数を利用して、[FEH] 種別毎の英雄ステータス平均値一覧のページで平均と標準偏差を計算している箇所がどの程度速くなるか検証してみました。
検証対象のソースコード
拡張関数を使用しないで平均と標準偏差を計算するソースコード
以下が拡張関数を使わずに自前で平均と標準偏差を計算していた置き換え前のソースコードです。平均の計算で array_sum を使っていないのは、array_sum を使うにはデータベースから一度配列を作らないといけなくて、そちらの方が処理コストが高かったためです。
$sum = 0;
$count = 0;
while($data = getNextData($db))
{
$sum += $data;
++$count;
}
$average = $sum / (float)$count;
$disp = 0;
$queryResult = $db->queryWrap($sql);
while($data = getNextData($db))
{
$disp += ($average - $data) * ($average - $data);
}
$disp = $disp / (float)$count;
$stdDev = sqrt($disp);
拡張関数を使用して平均と標準偏差を計算するソースコード
以下が置き換え後のstats拡張の stats_standard_deviation を使用したソースコードです。こちらでは一度データベースから配列を作るのは必須となるため、array_sum を使って平均を求めています。
$array = array();
while($data = getNextData($db))
{
$array[] = $data;
}
$count = count($array);
$average = array_sum($array) / (float)$count;
$stdDev = stats_standard_deviation($array);
計測内容と結果
上記のソースコードで検証ページを表示するのと同等の計算を 300 回繰り返して、その時間の平均を求めて比較しました。300 回にした理由は PHP がデフォルトでタイムアウト扱いにする 30 秒に引っかからない時間でちょうどよかったためです。検証時の疑似コードは以下のコードのような感じです。
<?php
$time_start = microtime(true);
$tryCount = 300;
for ($i = 0; $i < $tryCount ; ++$i)
{
calcAverageAndStandardDeviation();
}
$time = microtime(true) - $time_start;
$avgTime = $time / (float)$tryCount ;
print("{$time} sec");
print("<br/>{$avgTime} sec");
?>
計測結果は以下のようになりました。
置き換え前(拡張関数未使用) | 73 ms |
---|---|
置き換え後(拡張関数使用) | 48 ms |
処理時間の短縮率 | 0.65 |
置き換え前だとデータベースからのフェッチが2回走っていたので、それが1回に減ったことが大きかった可能性はありますが、全体としてはそれなりに高速化されたことがわかりました。拡張関数への置き換えによって、パフォーマンスもメンテナンスも向上したので一石二鳥です。
他にも置き換えられそうな処理があったら積極的に置き換えたいと思います。