4

考虑以下两个代码示例:

示例 1。

public void setValue(int value)
{
    mValue = value;
}

示例 2。

public void setValue(int value)
{
    if (mValue != value)
    {
        mValue = value;
    }
}

假设您的任务是优化一些 Java 代码到绝对最大值,超出所有常识。

第二个代码示例会是第一个代码示例的优化吗?我的意思是,在 Java 或 JVM 的最低级别的 if 条件检查和 int 赋值之间是否有任何区别(无论多么微小)?

4

4 回答 4

9

第二个可能是反优化,因为在现代处理器上,分支往往很昂贵(主要是因为分支错误预测的成本非常高)。

唯一确定的方法是在代表性输入上分析您的代码。请参阅如何在 Java 中编写正确的微基准测试?有关如何设置有意义的微基准的一些指示。

请记住,如果有问题的代码不占整个 CPU 时间的很大一部分,那么世界上的所有优化都不会对应用程序的整体性能产生很大影响。

于 2013-01-05T20:33:13.140 回答
3

NPE 有很好的建议。我要补充的一条评论是,这可能还取决于是否mValue易失,以及您正在运行它的硬件。对于易失性,写入可能比读取昂贵几倍。一些硬件(例如,我相信许多移动设备)易失性读取远非便宜,因此这种差异可能会缩小。

于 2013-01-05T20:42:43.387 回答
1

您可以尝试编译两者,然后使用 java 字节码反汇编程序来检查差异。Wikipedia JVM 指令列表可能是一个不错的起点。

根据我对使用过的编译器和 VM 的了解,由于额外的比较操作,第二个代码片段可能会(微不足道)慢一点。

如果您的 JVM 实现有一个优化器,它可能能够将您的第一个代码示例减少到一个操作,而第二个片段将需要至少一个或两个更多的操作来解释比较操作。

于 2013-01-05T20:36:39.187 回答
0

良好的编码实践说:“在最后一刻之前延迟优化”

但是代码测试说:

  • 总计(1)=1000000000 1420ms 总计(2)=1000000000 2155ms
  • 总计(1)=1000000000 1374ms 总计(2)=1000000000 1884ms
  • 总计(1)=1000000000 1379ms 总计(2)=1000000000 2072ms

比较和设置不是更好。

// Test Code
public class CompareAndSet {
    int mValue;

    // 1
    public void setValue1(int value) {
        mValue = value;
    }

    // 2
    public void setValue2(int value) {
        if (mValue != value) {
            mValue = value;
        }
    }

    public static void main(String[] args) {
        final int TOTAL = (int) 1e9;
        long ts;
        for (int j = 0; j < 3; j++) {
            // 1
            {
                ts = System.currentTimeMillis();
                CompareAndSet cs = new CompareAndSet();
                for (int i = 0; i < TOTAL; i++) {
                    cs.setValue1(i);
                }
                System.out.println("TOTAL(1)=" + TOTAL + " "
                        + (System.currentTimeMillis() - ts) + "ms");
            }
            // 2
            {
                ts = System.currentTimeMillis();
                CompareAndSet cs = new CompareAndSet();
                for (int i = 0; i < TOTAL; i++) {
                    cs.setValue2(i);
                }
                System.out.println("TOTAL(2)=" + TOTAL + " "
                        + (System.currentTimeMillis() - ts) + "ms");
            }
        }
    }

}
于 2013-01-05T20:52:17.500 回答