[英]Additional 'if checks' if the value is already set up - what is faster, what uses more resources?
假设我们有一个给定的接口:
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()
可以被多次调用1次,很难说调用次数的上限是多少。
问题是根据执行速度,垃圾收集,内存分配等,两种实现中的哪种方法“更好” - negateWithCheck
或negateWithoutCheck
?
答案取决于我们使用的两个提议的实现中的哪个或无关紧要?
答案取决于估计的通话次数吗? 对于使用一种或第一种方法更好的数量?
通常,如果需要设置某个状态,只需设置状态即可。 另一方面,如果你需要做更多的事情 - 比如记录变更,告知变更等等 - 那么你应该首先检查旧值。
但是,在非常强烈地调用您提供的方法之类的方法的情况下,检查与非检查的性能可能有所不同(新值是否有所不同)。 可能的结果是:
1-a)检查返回false
1-b)检查返回true,分配值
2)没有检查就分配了价值
据我所知,写入总是慢于读取(一直到注册级别),因此最快的结果是1-a。 如果您的情况是最常见的情况是该值不会被更改(“超过50%”的逻辑就不够好,必须凭经验确定确切的百分比)-那么您应该检查一下,因为这消除了多余的写入操作(值分配)。 另一方面,如果价值不同于经常的不同 - 分配它而不检查。
您应该测试具体案例,进行一些分析,然后根据结果确定最佳实施。 在这种情况下,没有通用的“最佳方法”(除了“仅设置状态”之外)。
至于这里的布尔值与布尔值,我会(不屑一顾)说应该没有性能差异。
简答:无检查总是会更快。
与比较相比,分配花费的计算时间少得多。 因此:IF语句总是比赋值慢。
comparing
2个变量时,CPU将获取第一个变量,获取第二个变量,比较这些变量并将结果存储到临时寄存器中。 那是2 fetch
1 store
es, 1 compare
和1 store
。
assign
值时,CPU将获取'='右侧的值并将其存储到内存中。 那是1 fetch
和1 store
。
使用支票时可能会有轻微的性能优势。 我非常怀疑这对任何现实生活中的应用都至关重要。
过早优化是万恶之源(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));
}
}
我得到以下内容:
check no check
primitive 17ms 24ms
Object 21ms 24ms
当检查总是多余的时候,我没有发现检查的任何性能损失,因为总是需要更改该值。
两件事:(1)这些时间不可靠。 (2)此基准远非任何实际应用; 我不得不制作一个包含1000万个元素的数组来实际看到的东西。
我只是选择没有检查的功能。 我高度怀疑在任何实际应用程序中,具有该检查功能的功能是否会获得任何可衡量的性能优势,但是该检查易于出错并且更难阅读。
直到今天,我才看到很少的答案和评论重复这一点
过早优化是万恶之源
好吧,显然, if
多说几句是一件要做的事,但是...这并不重要。
垃圾收集和内存分配......这里不是问题。
我通常会认为negateWithCheck稍微慢一点,因为总是有比较。 另请注意,在StateKeeperOfObjects中,您正在引入一些自动装箱。 “ true”和“ false”是原始布尔值。
假设您修复了StateKeeperOfObjects以使用所有对象,则可能,但是很可能不会引起注意。
速度将略微取决于呼叫的数量,但一般来说,无论您是呼叫一次还是多次,速度都应该被认为是相同的(忽略辅助效果,如缓存,jit等)。
在我看来,一个更好的问题是性能差异是否明显。 我正在研究一项涉及数百万并行数值计算的科学项目。 我们从使用对象(例如Integer,Double)开始,在内存和速度方面都没有令人满意的性能。 当我们将所有计算切换为基元(例如int,double)并查看代码以确保我们没有通过自动装箱引入任何时髦时,我们看到了巨大的性能提升(内存和速度)。
我非常喜欢避免过早优化,除非它是“简单”实现的东西。 只是要警惕后果。 例如,您是否必须在数据模型中表示空值? 如果是这样,您如何使用原语呢? 使用NaN可以轻松完成双打,但是布尔值呢?
negateWithoutCheck()是可取的,因为如果我们考虑调用次数,则negateWithoutCheck()仅具有一个调用,即this.b = false;。 其中negateWithCheck()与上一个有一个额外的区别。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.