少し前から時計がまたはやっていますね。
TeraClockとか便利なものが出てきたので、早速使わせてもらってます。

さて、TeraClock開発の話でTimerよりEnterFrameの方がいいとかパフォーマンスを気にされているようなんですが マイフレームごとにnew Date()してるのが気になったので実際どうすると効率がいいのか確認してみました。

まず3つ時刻を更新して取得する方法を考えてみました。

// 方法1) 普通にnewする var now = new Date();

// 方法2) newは初回のみで、差分(経過時間)を足してアップデート var _date:Date = new Date(); var _startTime:Date = _date.getTime(); _date.setTime( _startTime + getTimer() );

// 方法3) 方法2のtimeプロパティ利用したとき var _date:Date = new Date(); var _startTime:Date = _date.time; _date.time = _startTime + getTimer();

またこれを計測するのにベンチマークを簡単に出せるクラスつくりました タスクとなる関数を引数にしてnewして、startメソッドにループする回数を引数に実行します。

var benchmark :Benchmark = new Benchmark( function(){} ); benchmark.start( 1000000 );

すると次のように表示されます

Benchmark.start( x 1000000) at 3 Benchmark.end( total 2538 msec ) at 2541

計測してみる

用意したコードはこちらです。

import com.kayac.utils.Benchmark; import flash.utils.getTimer; // 方法1 var bm1 :Benchmark = new Benchmark( function(){ var date1 :Date = new Date(); var a:uint = date1.date; } ); bm1.start( 1000000 ); // 方法2 var date2 :Date = new Date(); var startTime1 = date2.getTime(); var bm2 :Benchmark = new Benchmark( function(){ date2.setTime( startTime1+getTimer() ); var b:uint = date2.date; } ); bm2.start( 1000000 ); // 方法3 var date3 :Date = new Date() var startTime2 = date3.getTime(); var bm3 :Benchmark = new Benchmark( function(){ date3.time = startTime2+getTimer(); var c:uint = date3.date; } ); bm3.start( 1000000 );

結果です

// 方法1 Benchmark.start( x 1000000) at 3 Benchmark.end( total 2985 msec ) at 2988 // 方法2 Benchmark.start( x 1000000) at 2989 Benchmark.end( total 2434 msec ) at 5423 // 方法3 Benchmark.start( x 1000000) at 5423 Benchmark.end( total 2653 msec ) at 8076

結論はnewでも大丈夫

ということで、やはりnewするケースが一番遅く、ひとつのDateクラスをsetTimeで更新するのが一番早いみたいでした。
AS3から追加されたtimeプロパティは、おそらくsetTime,getTimeのエイリアスなのでしょうか、すごく微妙に遅いですね。

ただ、100万回やってこの差なので、いくらnewが重いといっても実際にはこのライブラリ単体ではさほど問題ないでしょう。
差分を更新する方法だと逆に数値の精度面で不安がでてきてしまうので、秒間30回程度ならnewするほうがよいように思いました。

あとTeraClockの設計について思うところがあるのですが、それは次の機会にまとめたいとおもいます。

Benchmark.as

ついでなのでベンチマークのクラスも晒しておきます。

package com.kayac.utils { import flash.utils.getTimer; public class Benchmark { protected var _task:Function; protected var _arg;Array; protected var _startTime:uint; public function Benchmark( task:Function, arg:Array = null ) { _task = task; _arg = arg; } public function start( count:uint = 5000 ) { preTask( count ); for ( var i:uint = 0; i < count; ++i ) { _task.apply( null, _arg ); } postTask( count ); } private function preTask( count:uint ) { _startTime = getTimer(); print( "Benchmark.start( x "+count+") at ",_startTime ); } protected function print( ...rest:Array ):void{ trace.apply(null, rest); } private function postTask( count:uint ) { var endTime:uint = getTimer() - _startTime; print( "Benchmark.end( total "+endTime+" msec ) at ",getTimer() ); } } }

HTML5飯