Java 为什么在这个方法中添加一个If语句会大大降低它的速度?
这是我在一次旅行中偶然发现的。我试图诊断哪个代码更改对速度有更大的影响。我在for循环中使用了一个布尔标志,在使用helper方法来构造 有趣的是,当我决定哪一个更快时,删除了if,代码的速度放大了10倍。前140毫秒,后13毫秒。我应该只从循环中删除大约7个计算中的一个。为什么速度会有如此大的提高Java 为什么在这个方法中添加一个If语句会大大降低它的速度?,java,android,performance,Java,Android,Performance,这是我在一次旅行中偶然发现的。我试图诊断哪个代码更改对速度有更大的影响。我在for循环中使用了一个布尔标志,在使用helper方法来构造 有趣的是,当我决定哪一个更快时,删除了if,代码的速度放大了10倍。前140毫秒,后13毫秒。我应该只从循环中删除大约7个计算中的一个。为什么速度会有如此大的提高 慢速代码:(当helperMethods为false时,将在141毫秒内运行)*请参见编辑2 public static void applyAlphaGetPixels(Bitmap b, Bit
慢速代码:(当
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);
}
编辑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);
}
}
}
publicstaticvoidapplyalphagetpixel(位图b、位图bAlpha、布尔帮助方法){
int w=b.getWidth();
inth=b.getHeight();
对于(int y=0;y
注意:所有速度平均为100次运行。在“快速代码”中,您从未运行过该语句
colorPixels[j] = Color.argb(Color.alpha(alphaPixels[j]), Color.red(colorPixels[j]), Color.green(colorPixels[j]), Color.blue(colorPixels[j]));
但在“慢代码”中,如果布尔值至少在运行此附加语句后设置为true,则会延长时间。如果您的条件始终为false,那么在循环的每次迭代中,If语句将被检查大约7次。尝试将if放置在回路外部。尝试将条件提升到回路外部:
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]);
}
}
if(帮助方法){
对于(int j=0;j
可能是您的评测代码让您感到困惑。试着隔离你想要分析的代码部分,只测量那部分,避免在你的案例中创建位图之类的GCable操作
如果我调用你的测试代码
testing.loadDrawable(this, false, true, false)
它跑得很慢。但如果我把它叫做
testing.loadDrawable(this, true, true, false)
这是一个类似(更糟糕)的数字。因此,useGetPixels带来了所有的不同。我猜这会将位图数据放入本地缓冲区,稍后再设置结果。在fast代码中,您根本不使用类颜色。我假设这个类的初始化需要一些时间,它有很多静态方法和静态代码 您可以尝试执行以下操作:
在进行测试之前,确保Color类已完全加载并初始化(在调用ApplyalPhagentPixels()方法之前,可以从Color类调用任何静态方法)。然后运行测试并比较结果。if语句可能使代码更难优化。分支/分支预测?Traceview可能会愚弄您,因为这将禁用JIT。请提供更详细的信息。在哪种情况下是多快?刚刚删除了if或if及其主体?
helperMethods
对于整个循环为true/false。所以这不可能是分支预测,这很有趣。看起来情况也一样。在143ms内使用helperMethods
false运行。不过分支预测应该能很好地处理它。。。嗯,我试过了,代码运行速度仍然很慢。快了8毫秒,很有趣。大O分析…:)我不认为它在技术上是大O,因为它是由一个算法运行的时间与数据集相比来定义的。对。然而,它一定是消耗时间的东西,可能是在较低级别的某个地方,这听起来像是我的错误如果问题是GC,这不意味着只有第一次运行会很快,因为只有后面的运行会因为GC清除早期测试而陷入困境吗?这也是我所听说的GC对性能影响最大的一次,而且似乎是无中生有。我如何预测GC何时会导致如此大规模的问题?这感觉我接近答案了,但我仍然想知道到底发生了什么。在这个答案中,我并不声称问题是由于GCs造成的,但您的代码太乱,无法正确地进行分析。我相信您的问题是useGetPixels
,当您启用它时,运行时间会增加。否则,if
as-clain不会改变运行时间。所以我很困惑。你是说getPixels的运行时间增加了?对我来说,每次都更快。您的“快速”版本是loadDrawableHard(this,true,true)
。我改了名字,这样我就能很容易地分辨出哪个是硬编码的。在这个版本中,除了调用了applyalphagettpixelshard()
和'applyGetPixelHard()`之外,所有代码都是相同的。如果我在运行时将useGetPixels
设置为false,我看不到同样的改进。我最初编写的loadDrawableHard()
只使用applyAlphaGetPixelsHard()
,但添加了applyGetPixelHard()
以消除可能的差异。我简直不敢相信
testing.loadDrawable(this, false, true, false)
testing.loadDrawable(this, true, true, false)