Java 附加';如果检查';如果已经设置了值-什么更快,什么使用更多的资源?

Java 附加';如果检查';如果已经设置了值-什么更快,什么使用更多的资源?,java,jvm,micro-optimization,premature-optimization,microbenchmark,Java,Jvm,Micro Optimization,Premature Optimization,Microbenchmark,假设我们有一个给定的接口: public interface StateKeeper { public abstract void negateWithoutCheck(); public abstract void negateWithCheck(); } 以及以下实现: class StateKeeperForPrimitives implements StateKeeper { private boolean b = true; public vo

假设我们有一个给定的接口:

public interface StateKeeper {

    public abstract void negateWithoutCheck();

    public abstract void negateWithCheck();

}
以及以下实现:

class StateKeeperForPrimitives implements StateKeeper {
    private boolean b = true;

    public void negateWithCheck() {
        if (b == true) {
            this.b = false;
        }
    }

    public void negateWithoutCheck() {
        this.b = false;
    }
}

class StateKeeperForObjects implements StateKeeper {
    private Boolean b = true;

    @Override
    public void negateWithCheck() {
        if (b == true) {
            this.b = false;
        }
    }

    @Override
    public void negateWithoutCheck() {
        this.b = false;
    }
}
此外,假设可以多次调用方法
negate*Check()
,很难说调用次数的上限是多少

  • 问题是两种实现中哪种方法“更好” 根据执行速度、垃圾收集、内存分配等-
    negateWithCheck
    negateWithoutCheck

  • 答案是否取决于这两个建议中的哪一个 我们使用的实现还是无关紧要

  • 答案是否取决于估计的呼叫数?使用onefirst方法对数字的哪个计数更好


通常,如果需要设置某些状态,只需设置状态即可。另一方面,如果您需要做更多的事情,比如记录更改、通知更改等,那么您应该首先检查旧值

但是,在像您提供的方法这样的方法被强烈调用的情况下,检查与不检查可能会有一些性能差异(新值是否不同)。可能的结果是:

1-a)检查返回假
1-b)检查返回true,赋值
2) 未经检查就分配了值

据我所知,写作总是比阅读慢(一直到寄存器级别),所以最快的结果是1-a。如果您的情况是,最常见的情况是不会更改值(“超过50%”的逻辑不够好,必须根据经验计算出确切的百分比),那么您应该进行检查,因为这消除了冗余的写入操作(值分配)。另一方面,如果值与通常值的差异更大,则无需检查即可分配该值

您应该测试您的具体案例,进行一些分析,并根据结果确定最佳实现。对于这种情况,没有通用的“最佳方法”(除了“仅设置状态”)


至于布尔与布尔的比较,我会毫不犹豫地说,应该没有性能差异。

直到今天,我才看到一些答案和评论重复这一点

过早优化是万恶之源

很明显,一个
如果
语句更多是一件事要做,但是。。。这并不重要

以及垃圾收集和内存分配。。。这不是问题

我通常认为否定的检查要稍微慢一些,因为总是有比较。另外请注意,在StateKeeperOfObjects中,您引入了一些自动装箱true和false是基本布尔值

  • 假设您修复了StateKeeperOfObjects以使用所有对象,那么可能是,但很可能不是显而易见的

  • 速度将略微取决于调用的数量,但通常情况下,无论调用一次还是多次,速度都应被视为相同(忽略缓存、jit等辅助效果)

  • 在我看来,更好的问题是性能差异是否明显。我在一个科学项目上工作,该项目涉及数百万并行的数值计算。我们开始使用对象(例如Integer、Double),但在内存和速度方面的性能都不理想。当我们将所有的计算转换为原语(例如int、double)并检查代码以确保我们没有通过自动装箱引入任何古怪的东西时,我们看到了巨大的性能提升(内存和速度)


    我非常喜欢避免过早优化,除非它是“简单”实现的。只是要小心后果。例如,您是否必须在数据模型中表示空值?如果是这样,您如何使用原语来实现这一点?双打可以用楠轻松完成,但是Booleans呢?

    < P>NefAuthOutAuthCuffor()是最好的,因为如果我们考虑调用的次数,则否定项只有(一个)调用,也就是这个。其中as negateWithCheck()与前一个有一个额外的值。

    简短回答:没有检查的总是更快

    与比较相比,赋值所需的计算时间要少得多。因此:IF语句总是比赋值慢

    当比较两个变量时,CPU将获取第一个变量,获取第二个变量,比较这两个变量,并将结果存储到临时寄存器中。这就是
    2获取
    es、
    1比较
    1存储

    当您
    分配一个值时,您的CPU将获取“=”右侧的值并将其存储到内存中。这就是
    1fetch
    1store

    使用带有检查的一个可能会有轻微的性能优势。我高度怀疑它在任何实际应用程序中是否重要

    过早优化是万恶之源(Donald Knuth)


    你可以测量两者之间的差异。让我强调一下,这类东西众所周知很难可靠地测量。

    下面是一个简单的方法。如果检查确认不必更改该值,那么您可以希望获得性能方面的好处,从而节省对内存的昂贵写入。所以我相应地修改了你的代码

    interface StateKeeper {
    
        public abstract void negateWithoutCheck();
    
        public abstract void negateWithCheck();
    
    }
    
    class StateKeeperForPrimitives implements StateKeeper {
    
        private boolean b = true;
    
        public void negateWithCheck() {
            if (b == false) {
                this.b = true;
            }
        }
    
        public void negateWithoutCheck() {
            this.b = true;
        }
    }
    
    class StateKeeperForObjects implements StateKeeper {
    
        private Boolean b = true;
    
        public void negateWithCheck() {
            if (b == false) {
                this.b = true;
            }
        }
    
        public void negateWithoutCheck() {
            this.b = true;
        }
    }
    
    public class Main {
    
        public static void main(String args[]) {
    
            StateKeeper[] array = new StateKeeper[10_000_000];
    
            for (int i=0; i<array.length; ++i)
                //array[i] = new StateKeeperForObjects();
                array[i] = new StateKeeperForPrimitives(); 
    
            long start = System.nanoTime();
    
            for (StateKeeper e : array)
                e.negateWithCheck();
                //e.negateWithoutCheck();
    
            long end = System.nanoTime();
    
            System.err.println("Time in milliseconds: "+((end-start)/1000000));
        }
    }
    
    当检查总是多余的时候,我没有发现检查的任何性能损失,因为值总是需要更改的

    两件事:(1)这些时间安排不可靠。(2) 这个基准远非任何实际应用程序;我必须制作一个包含1000万个元素的数组才能真正看到一些东西

    我只会选择不需要检查的函数。我非常怀疑这一点
               check  no check
    primitive   17ms    24ms
    Object      21ms    24ms