データ移行用のスクリプトをPHPで作成していて、移行するデータの変換で何万回も呼び出されるメソッドがあったんですが、リファクタリングしてそのメソッドから別クラスを呼び出すようにしました。
で気になったのが、メソッドが呼ばれる度にそのクラスインスタンスを都度生成するのって遅くなるんじゃ無いかってコトでした。
クラスを new するたびに何かしら実行されるんだから、その分遅くなるのは当然として、それでどのぐらい遅くなるのかが気になりました。
インスタンス生成に結構時間かかるなら、シングルトンにするとかどこかであらかじめ生成したのを渡して呼び出すようにするとか工夫がいるかも?っておもったんですね。
というわけで実験。
コンストラクタの無いクラス
最初の実験はコンストラクタの無いクラスの生成時間測定。
下記コードで同じクラスのインスタンスを100万回生成してからmain()を呼び出すのと、あらかじめ1回生成しておいて100万回main()を呼び出すだけのケースで比較。
class NoConstructor
{
public function main() {
return date('YmdHis');
}
}
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$obj = new NoConstructor();
$result = $obj->main();
unset($obj);
}
$end = microtime(true);
$time = $end - $start;
var_dump($time);
$start = microtime(true);
$obj = new NoConstructor();
for ($i = 0; $i < 1000000; $i++) {
$result = $obj->main();
//unset($obj);
}
$end = microtime(true);
$time = $end - $start;
var_dump($time);
結果は、100万回生成&main()実行のケースで 3.40秒 。
1回だけ生成して100万main()実行のケースで 3.08秒 。
100万回の生成をしても 0.38秒しか余分に時間かかってません。
これだったら無理にシングルトン化するとかしなくても良さそうです。
コンストラクタがあるクラス
次にコンストラクタがあるクラスで同様の計測をします。
class UseConstructor
{
private $value = null;
public function __construct() {
$this->value = date('YmdHis');
}
public function main() {
return $this->value;
}
}
$start = microtime(true);
for ($i = 0; $i < 1000000; $i++) {
$obj = new UseConstructor();
$result = $obj->main();
unset($obj);
}
$end = microtime(true);
$time = $end - $start;
var_dump($time);
$start = microtime(true);
$obj = new UseConstructor();
for ($i = 0; $i < 1000000; $i++) {
$result = $obj->main();
//unset($obj);
}
$end = microtime(true);
$time = $end - $start;
var_dump($time);
こっちの結果は
100万回生成が 4.51秒。
1回だけが 1.30秒。
コンストラクタでの処理が重くてメソッドの実装が軽いようなケースではハッキリ差がでますね。
というわけでコンストラクタが無ければあまりインスタンス生成の処理時間を気にしなくても良さそうでした。