我在answering another question中遇到过这个问题。我试图诊断哪个代码更改对速度有更大的影响。我在for循环中使用了一个布尔标志来在使用辅助方法之间切换来构造Color。
有趣的行为是,当我决定哪一个更快并删除时,如果代码的速度放大了10倍。以前需要140ms,之后只需13ms。我应该只从循环中删除大约7个计算。为什么速度如此急剧增加?
慢代码( *参见编辑2 helperMethods
为假时运行141毫秒)
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
。代码运行速度稍快但仍处于131ms的低速:
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次。
答案 0 :(得分: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]);
}
}
答案 1 :(得分:2)
在“快速代码”中,您永远不会运行语句
colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]), Color.red(colorPixels[j]), Color.green(colorPixels[j]), Color.blue(colorPixels[j]));
但是在'慢代码'中,如果布尔值至少设置为true,则运行此addiotional语句会使时间更长。如果您的条件总是为假,则在循环的每次迭代中检查if语句大约7次。尝试将if置于循环之外。
答案 2 :(得分:2)
这可能是你的分析代码,让你感到困惑。尝试隔离要分析的代码部分并仅测量该部分,避免GCable操作,例如在您的情况下创建位图。
如果我用
调用您的测试代码testing.loadDrawable(this, false, true, false)
它运行缓慢。但如果我用
来称呼它testing.loadDrawable(this, true, true, false)
这是一个类似的(更糟糕的)数字。所以useGetPixels会发挥重要作用。我想将Bitmap数据放入本地缓冲区并稍后设置结果。
答案 3 :(得分:0)
在快速代码中,根本不使用类Color。我假设这个类的初始化需要一些时间,它有很多静态方法和静态代码。
您可以尝试执行以下操作: 确保在进行测试之前完全加载和初始化Color类(可以在调用applyAlphaGetPixels()方法之前调用Color类中的任何静态方法)。然后运行测试并比较结果。