0

数か月前にこの 2D ウォーター デモを作成し ( http://nauful.com/Qasim/Pani.html )、常に呼び出される (ENTER_FRAME) waveHandler と呼ばれるコア レンダリング関数を備えています。

ここでは、多数の画像処理の変位マップ/畳み込みが行われていますが、それは実際には関係ありません。この waveHandler 関数で行われていることを変更したいのですが、ここで常に実行される IF ステートメントを使用したくありません。たとえば、この偽の後処理のブルーム/反射率が進行中で、古いマシンでは動きがとれなくなる傾向があります (~ を押すと FPS カウンターが表示されます)。 IF ステートメントは、ブール変数の値を常にチェックします。

これを行うための非常に洗練されていない冗長な方法の 1 つは、これらのオプションの順列を処理する複数のバージョンの waveHandler を用意し、1 つのバージョンのリスナーを削除して別のバージョンを有効にすることです。しかし、どうすればこれを適切に行うことができますか?

また、変数に関数を「指す」ようにさせることは可能ですか? そのため、var asdf:Function が一度に 1 つの関数を指し、その後 asdf の値が別の関数を指すように変更された場合、メイン関数は、条件文を常にチェックすることなく、asdf が指す関数を呼び出すことができます。

ありがとう!

4

2 に答える 2

0

後者は確かに可能ですが、その変数をaddEventListener呼び出しに入れることはできません。しかし、あなたはこのようにすることができます:

function onEnterFrame(e:Event):void {
    if (asdf) asdf();
}

そして、正しい関数を指すようにasdf変数を設定します。ただし、引数セットが均一でない関数にはこのアプローチを使用しないでください。たとえば、1つの関数に1つのint引数があり、別のゼロ引数がある場合は、例外がスローされます。

しかし、条件を考えると、ブール値を1回チェックする方が、変数を介して関数を呼び出すよりもコストがかからないため、ブール値のifステートメントを使用します。

于 2012-10-14T04:58:05.057 に答える
0

最も速いのはあなたが提案したものです:オプションの順列ごとに1つのwaveHandlerを持っています。オプションが有効になっている場合に最速になり、オプションが無効になっている場合に最速になります。

あなたが自分で提案した別のアプローチ:関数への参照を持ち、オプションを有効または無効にするために参照を変更します。そして、空の関数を指すように参照を変更することで「無効化」できます。このようなもの:

package {
    import flash.display.Sprite;
    import flash.utils.getTimer;

    public class Main extends Sprite {
        private var call1: Function;
        private var call2: Function;
        private var call3: Function;

        public function Main() : void {
            var doOption1 : Boolean = true;
            var doOption2 : Boolean = false;
            var doOption3 : Boolean = true;

            call1 = doOption1 ? option1 : empty;
            call2 = doOption2 ? option2 : empty;
            call3 = doOption3 ? option3 : empty;

            onEnterFrame();
        }

        private function onEnterFrame():void {
            call1();
            call2();
            call3();
        }

        private function option1():void {
            trace("option1");
        }

        private function option2():void {
            trace("option2");
        }

        private function option3():void {
            trace("option3");
        }

        private function empty():void {
        }
    }
}

これにより、オプションが有効になっている場合のパフォーマンスが低下することはありませんが、空の関数を呼び出しているため、オプションが無効になっている場合は、最初のソリューションと比較してペナルティが発生するため、オーバーヘッドが小さくなります。

この質問全体がより学術的なタイプであった可能性があることを私は知っています、そしてあなたはそれが実際にパフォーマンスに目立った違いをもたらさないことをすでに知っています。

しかし、パフォーマンスの観点からは、ifケースがそれよりも悪いと思うように聞こえます。私はそれらに固執し(非常に読みやすいコードになるため) 、測定可能な影響を与えることができるコードの部分を最適化することに焦点を当てます。

いくつかのブールチェックがどれほど重要でないかを理解するために、簡単なテストを行いました。2つの異なるonEnterFrame関数があります。どちらも空の関数を10回呼び出します。最初のものは「プレーン」です(10回の連続呼び出し)。もう1つは、メソッドを呼び出す前にフラグがtrueであることを確認します。

私のかなり標準的なラップトップでは、最初の結果は次のようになりました。

プレーン:3133ミリ秒
ifチェックあり:3167ミリ秒
1000000 onEnterFrame呼び出しの差:34ミリ秒
onEnterFrame呼び出しごとの差:0.000034ミリ秒

差が非常に小さいため、100万回の呼び出しを行っても測定が困難です(最初の実行後の一部のテスト実行では、ifチェックを使用したバージョンの方が実際に高速でした)。

これは、最適化に関しては、より科学的なアプローチをとる必要があるという言い方です。そうしないと、最適化に多くの時間を費やしてしまい、代わりにコードの読み取りと保守が難しくなります。速度の向上はほとんどまたはまったくありません。ここでそれをしました:-)

最後に、自分で実行する場合のテストは次のとおりです。

package {
    import flash.display.Sprite;
    import flash.utils.getTimer;

    public class Main extends Sprite {
        private var m_flag: Boolean = true;

        public function Main() : void {
            var callCount : int = 1000000, time1 : int, time2 : int, i : int;

            i = callCount;
            time1 = getTimer();
            while (i-- > 0) {
                onEnterFrame1();
            }
            time1 = (getTimer() - time1);

            i = callCount;
            time2 = getTimer();
            while (i-- > 0) {
                onEnterFrame2();
            }
            time2 = (getTimer() - time2);

            trace("Plain: " + time1 + " ms");
            trace("With if checks: " + time2 + " ms");
            trace("Difference for " + callCount + " onEnterFrame calls: " + (time2 - time1) + " ms");
            trace("Difference per onEnterFrame call:  " + ((time2 - time1) / callCount) + " ms");
        }

        private function onEnterFrame1():void {
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
            emptyMethod();
        }

        private function onEnterFrame2():void {
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
            if (m_flag) emptyMethod();
        }

        private function emptyMethod():void {
        }
    }
}
于 2012-10-14T10:02:09.010 に答える