31.すごく時間のかかる処理

ループの間は画面が更新されない

FLASHでものすごく時間のかかる処理をやろうとすると、その間画面が更新されません。

例えば、下のような単純なループ。

for (var ii:uint=0;ii<100000;ii++){
//なにかの処理
}

このループを実行中はムービーは固まったようになりますよね。for文に限らずwhile文でも同じです。

通常FLASHのムービーでそんな状況って少ないと思いますが、考えられるのは将棋や碁、チェスなどのゲームの思考ルーチンなどでしょうか。

とにかく計算量が多いわけです。

その間、画面を固まらせておくのって嫌ですよね。

せめて「次の手を考えてますよ〜」というムービーなり、進捗率を表示するなり、なにかしらの表示をしたいわけです。

ここは、その対策についてのメモです。

ENTER_FRAMEでやってみる

ENTER_FRAMEを使うとフレームの更新ごとに処理されるわけですから、そこに計算したい内容を入れておけば意図通りの動作をしてくれそうです。

コードにすると基本的な流れはこんな感じ。

var ii:uint=0;//カウント用
addEventListener(Event.ENTER_FRAME , EF);
function EF(e:Event):void {

//実際の計算内容(略)

//進行・終了判定
ii++;
if (ii == 100000){//終了か?
removeEventListener(Event.ENTER_FRAME , EF);
trace("終わり");
}
}

「実際の計算内容」というのは、将棋の次の一手を探すルーチンでもなんでもいいですが、メインの計算処理部分です。

単純ですがこういう構成にすれば、とりあえず動作します。

しかし、、、

もっと高速に処理したい!

しかし、です。

上記のコードの流れで計算させると、フレームレート(1秒間に何回フレーム更新をするか)と計算量により余力が生じる場合が予想されますよね。

つまりフレームレートを50FPSに設定すれば1フレームあたり、0.02秒あるわけですが、計算が簡単だと0.001秒で終わるかもしれない。

この時、残りの0.019秒はPCは「余裕こいてる」わけです。

さっさと計算して欲しいのに、CPU使用率はほんの数%だったりするんです。

じゃあどうしようか、ということでこんな対策を試してみました。

ENTER_FRAME内にwhile文を置き、その中でいちいち時間を測定し、時間ぎりぎりまで計算させるようにしてみました。

コードはこんな構成です。

var ii:uint=0;//カウント用
addEventListener(Event.ENTER_FRAME , EF);
function EF(e:Event):void {
var starttime:Number=new Date().getTime();//msec
while(1){
if (new Date().getTime()-starttime >= 1000/stage.frameRate*0.8){
break;
}else{
//実際の計算内容(略)

//進行・終了判定
ii++;
if (ii == 100000){//終了か?
removeEventListener(Event.ENTER_FRAME , EF);
trace("終わり");
break;
}
}
}
}

関数EFが処理される、つまりフレーム更新時、に毎回時間を記録しておき(starttime)、while文内で毎回、現在時刻と比較して計算するか、次のフレームへ行かせるかを決めてます。

なお、ここでは時間の単位はミリ秒です。

フレームレートstage.frameRateに8掛けしてるのは、、、まあ余裕見て、ってところでしょうか。気分的なもんです(^^;

で、実行してみると、、、

CPU使用率もアップして、計算時間も短縮することができました(^^)v

→32.正規分布

30.if文の謎←