13

我在回答另一个问题时遇到了这个问题。我试图诊断哪些代码更改对速度的影响更大。我在 for 循环中使用了一个布尔标志来在使用辅助方法构造Color之间切换。

有趣的行为是,当我决定哪一个更快并删除时,如果代码的速度放大了 10 倍。之前用了 140 毫秒,之后只用了 13 毫秒。我应该只从循环中删除大约 7 个计算中的一个。为什么速度有如此大幅度的提升?

慢代码:(helperMethods当为假时在 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);
}

快速代码:(在 13 毫秒内运行)

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,则至少在您运行这个使时间更长的附加语句时。如果您的条件始终为假,则在循环的每次迭代中检查 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 回答