13

私は別の質問に答える際にこれに出くわしました。どのコード変更が速度に大きな影響を与えたかを診断しようとしていました. for ループでブール値フラグを使用して、ヘルパー メソッドを使用してColorを構築する方法を切り替えました。

興味深い動作は、どちらが速いかを判断して、コードの速度が 10 倍に増幅された場合を削除したことです。前に 140 ミリ秒かかり、後はわずか 13 ミリ秒です。ループから約 7 つの計算のうち 1 つだけを削除する必要があります。なぜ、これほどまでに速度が大幅に向上したのでしょうか。

スロー コード:helperMethods (が false の場合、141 ミリ秒で実行されます) *編集 2 を参照

public static void applyAlphaGetPixels(Bitmap b, Bitmap bAlpha, boolean helperMethods) {
    int w = b.getWidth();
    int h = b.getHeight();
    int[] colorPixels = new int[w*h];
    int[] alphaPixels = new int[w*h];
    b.getPixels(colorPixels, 0, w, 0, 0, w, h);
    bAlpha.getPixels(alphaPixels, 0, w, 0, 0, w, h);
    for(int j = 0; j < colorPixels.length;j++){
        if(helperMethods){
            colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]), Color.red(colorPixels[j]), Color.green(colorPixels[j]), Color.blue(colorPixels[j]));
        } else colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
    }
    b.setPixels(colorPixels, 0, w, 0, 0, w, h);
}

高速コード: (13ms で実行)

public static void applyAlphaGetPixels(Bitmap b, Bitmap bAlpha) {
    int w = b.getWidth();
    int h = b.getHeight();
    int[] colorPixels = new int[w*h];
    int[] alphaPixels = new int[w*h];
    b.getPixels(colorPixels, 0, w, 0, 0, w, h);
    bAlpha.getPixels(alphaPixels, 0, w, 0, 0, w, h);
    for(int j = 0; j < colorPixels.length;j++){
        colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
    }
    b.setPixels(colorPixels, 0, w, 0, 0, w, h);
}

編集: if がループ内にあるという事実には問題がないようです。ifループの外側を上げると。コードはわずかに高速に実行されますが、それでも 131 ミリ秒と低速です。

public static void applyAlphaGetPixels(Bitmap b, Bitmap bAlpha, boolean helperMethods) {
    int w = b.getWidth();
    int h = b.getHeight();
    int[] colorPixels = new int[w*h];
    int[] alphaPixels = new int[w*h];
    b.getPixels(colorPixels, 0, w, 0, 0, w, h);
    bAlpha.getPixels(alphaPixels, 0, w, 0, 0, w, h);
    if (helperMethods) {
        for (int j = 0; j < colorPixels.length;j++) {
            colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]),
                                        Color.red(colorPixels[j]),
                                        Color.green(colorPixels[j]),
                                        Color.blue(colorPixels[j]));
        }
    } else {
        for (int j = 0; j < colorPixels.length;j++) {
             colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
        }
    }

    b.setPixels(colorPixels, 0, w, 0, 0, w, h);
}

編集2:私はばかです。ほんとうにばかだ。getPixelコール スタックの前半で、別のブール値フラグを使用して、このメソッドを使用するか、代わりにを使用する別のメソッドを使用するかを切り替えgetPixelsました。helperMethodパラメータを持つすべての呼び出しで、このフラグが間違って設定されていました。バージョンに新しい呼び出しを行ったときhelperMethod、正しく実行しませんでした。パフォーマンスの向上はgetPixels、if ステートメントではないためです。

実際のスロー コード:

public static void applyAlphaGetPixel(Bitmap b, Bitmap bAlpha, boolean helperMethods) {
    int w = b.getWidth();
    int h = b.getHeight();
    for(int y=0; y < h; ++y) {
        for(int x=0; x < w; ++x) {
            int pixel = b.getPixel(x,y);
            int finalPixel;
            if(helperMethods){
                finalPixel = Color.argb(Color.alpha(bAlpha.getPixel(x,y)), Color.red(pixel), Color.green(pixel), Color.blue(pixel));
            } else{
                finalPixel = bAlpha.getPixel(x,y) | (0x00FFFFFF & pixel);
            }
            b.setPixel(x,y,finalPixel);
        }
    }
}

注: すべての速度は 100 回の実行の平均です。

4

4 に答える 4

4

ループから条件を引き上げてみてください。

if (helperMethods) {
    for (int j = 0; j < colorPixels.length;j++) {
        colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]),
                                    Color.red(colorPixels[j]),
                                    Color.green(colorPixels[j]),
                                    Color.blue(colorPixels[j]));
    }
} else {
    for (int j = 0; j < colorPixels.length;j++) {
         colorPixels[j] = alphaPixels[j] | (0x00FFFFFF & colorPixels[j]);
    }
}
于 2012-09-02T23:21:24.033 に答える
2

「高速コード」では、ステートメントを実行することはありません

colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]), Color.red(colorPixels[j]), Color.green(colorPixels[j]), Color.blue(colorPixels[j])); 

ただし、「スロー コード」では、ブール値が true に設定されている場合、少なくとも 1 回はこの追加のステートメントを実行すると時間が長くなります。条件が常に false の場合、ループの各反復で if ステートメントが約 7 回チェックされます。if をループの外側に配置してみてください。

于 2012-09-02T23:17:50.747 に答える
2

あなたを混乱させているのは、おそらくあなたのプロファイリング コードです。プロファイリングするコードの部分を分離して、その部分を測定するようにしてください。ケースでビットマップを作成するなどの GCable 操作は避けてください。

テストコードを呼び出すと

testing.loadDrawable(this, false, true, false)

それはゆっくりと実行されます。しかし、私がそれを呼び出すと

testing.loadDrawable(this, true, true, false)

これは同様の (さらに悪い) 数値です。したがって、useGetPixels はすべての違いを生みます。ビットマップデータをローカルバッファーに取得し、後で結果を設定すると思います。

于 2012-09-03T11:53:10.523 に答える
0

高速コードでは、クラス Color をまったく使用しません。このクラスの初期化には時間がかかると思います。静的メソッドと静的コードがたくさんあります。

次のことを試すことができます: テストを行う前に、Color クラスが完全にロードされ、初期化されていることを確認してください (applyAlphaGetPixels() メソッドを呼び出す前に、Color クラスから任意の静的メソッドを呼び出すことができます)。次に、テストを実行して結果を比較します。

于 2012-09-03T13:18:17.597 に答える