OpenGL 渲染器循环中哪个更有效率:"if" 运算符或 lambda?
What is more productive in the OpenGL renderer loop: "if" operator or lambda?
开始渲染游戏时,部分算法发生变化(处理屏幕上的点击)。
有两种选择。
1.使用"if"运算符:
public class Leve1 implements GLSurfaceView.Renderer {
private boolean isLoadGame = false;
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
...
isLoadGame = true; // game is now loaded
}
// this method is called often in the render loop
public void setPassXY(float x, float y) {
if (isLoadGame) {
... // perform algorithm
}
}
}
2。使用 lambda(没有 "if"):
public class Leve1 implements GLSurfaceView.Renderer {
// when the game is not loaded yet use the empty method body
private PressXYInterface<Float, Float> pressXY = (pressX, pressY) -> {};
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
...
pressXY = (passX, passY) -> {
... // game is now loaded - add algorithm
};
}
// this method is called often in the render loop
public void setPassXY(float x, float y) {
pressXY.invoke(x, y); // perform algorithm
}
}
@FunctionalInterface
public interface PressXYInterface<T, U> {
void invoke(T x, U y);
}
问题:在性能方面使用哪种方法更好?
TL;DR - 没有一个正确答案。这取决于很多因素。对您的 真实 应用程序进行基准测试是获得可靠答案的唯一途径。
以下是一些问题:
一方面,使用 lambdas 的版本节省了 if
语句。
另一方面,使用方法调用的版本可能会被 JIT 编译器内联。 (这些 lambda 调用无法内联,因为在不同的时间点调用站点可能调用不同的 lambda。)
另一方面,如果// perform algorithm
足够复杂,它会太大而无法内联。
另一方面,如果 algorithm
太大而无法内联,也许 if
测试的成本将微不足道。
另一方面,if
测试可能比您想象的要便宜。例如:
- 如果代码在切换到
isLoadGame == true
状态后进行了 JIT 编译,那么统计信息可能会告诉 JIT 编译器针对测试成功的情况进行优化。
- (硬件)分支预测可能会根据该测试的模态行为进行调整。
另一方面,我不清楚哪些版本需要进行简单调用或虚拟调用。或者 JIT 编译器 是否可以 优化虚拟调用。我根本不知道。 (检查字节码会给出部分答案。)
然后就是JIT编译器版本不同,硬件ISA不同,硬件实现不同的问题
简而言之,预测哪种方法在现实中表现更好的因素太多了。
这也意味着微基准测试不太可能有帮助。上述许多因素将严重取决于实际应用程序代码和应用程序启动的方式。您将需要对实际应用程序进行基准测试以获得有意义的结果。
开始渲染游戏时,部分算法发生变化(处理屏幕上的点击)。
有两种选择。 1.使用"if"运算符:
public class Leve1 implements GLSurfaceView.Renderer {
private boolean isLoadGame = false;
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
...
isLoadGame = true; // game is now loaded
}
// this method is called often in the render loop
public void setPassXY(float x, float y) {
if (isLoadGame) {
... // perform algorithm
}
}
}
2。使用 lambda(没有 "if"):
public class Leve1 implements GLSurfaceView.Renderer {
// when the game is not loaded yet use the empty method body
private PressXYInterface<Float, Float> pressXY = (pressX, pressY) -> {};
public void onSurfaceChanged(GL10 glUnused, int width, int height) {
...
pressXY = (passX, passY) -> {
... // game is now loaded - add algorithm
};
}
// this method is called often in the render loop
public void setPassXY(float x, float y) {
pressXY.invoke(x, y); // perform algorithm
}
}
@FunctionalInterface
public interface PressXYInterface<T, U> {
void invoke(T x, U y);
}
问题:在性能方面使用哪种方法更好?
TL;DR - 没有一个正确答案。这取决于很多因素。对您的 真实 应用程序进行基准测试是获得可靠答案的唯一途径。
以下是一些问题:
一方面,使用 lambdas 的版本节省了 if
语句。
另一方面,使用方法调用的版本可能会被 JIT 编译器内联。 (这些 lambda 调用无法内联,因为在不同的时间点调用站点可能调用不同的 lambda。)
另一方面,如果// perform algorithm
足够复杂,它会太大而无法内联。
另一方面,如果 algorithm
太大而无法内联,也许 if
测试的成本将微不足道。
另一方面,if
测试可能比您想象的要便宜。例如:
- 如果代码在切换到
isLoadGame == true
状态后进行了 JIT 编译,那么统计信息可能会告诉 JIT 编译器针对测试成功的情况进行优化。 - (硬件)分支预测可能会根据该测试的模态行为进行调整。
另一方面,我不清楚哪些版本需要进行简单调用或虚拟调用。或者 JIT 编译器 是否可以 优化虚拟调用。我根本不知道。 (检查字节码会给出部分答案。)
然后就是JIT编译器版本不同,硬件ISA不同,硬件实现不同的问题
简而言之,预测哪种方法在现实中表现更好的因素太多了。
这也意味着微基准测试不太可能有帮助。上述许多因素将严重取决于实际应用程序代码和应用程序启动的方式。您将需要对实际应用程序进行基准测试以获得有意义的结果。