Java 使用日期和日期时的性能问题&;
在评估一些非常具体的if条件时,我遇到了一些非常奇怪的性能行为 基本上,我发现我可以构造两个条件a和b,使得Java 使用日期和日期时的性能问题&;,java,performance,date,Java,Performance,Date,在评估一些非常具体的if条件时,我遇到了一些非常奇怪的性能行为 基本上,我发现我可以构造两个条件a和b,使得if(a)比if(a&&b)快10倍,即使a始终为false,这似乎与Java应该对条件进行延迟求值的事实直接冲突 当我有a成为someDate.after(startdate)和b成为someDate.before(enddate)-即一个相当标准的范围条件时,就会发生这种情况 下面我附上了我用来展示这个特殊问题的代码。我已经用Java 7在Windows 7上运行了这段代码,我的一位同
if(a)
比if(a&&b)
快10倍,即使a
始终为false,这似乎与Java应该对条件进行延迟求值的事实直接冲突
当我有a
成为someDate.after(startdate)
和b
成为someDate.before(enddate)
-即一个相当标准的范围条件时,就会发生这种情况
下面我附上了我用来展示这个特殊问题的代码。我已经用Java 7在Windows 7上运行了这段代码,我的一位同事用Java 6、7和8在Windows 7上运行了这段代码——所有这些都得到了相同的结果
有人能解释为什么会发生这种情况吗
import java.util.Date;
public class DateWeirdness {
public static void main(String[] args) {
Date start = new Date();
System.out.println("if(a) - a always false");
System.out.println(timeBasic(2000000000, start, start.getTime() - 4000000000L));
start = new Date();
System.out.println("if(a && b) - a always false, a and b both date method");
System.out.println(timeAdv(2000000000, start, start.getTime() - 4000000000L, new Date()));
start = new Date();
System.out.println("if(a && b) - a always false, b is condition on longs not date");
System.out.println(timeAdv2(2000000000, start, start.getTime() - 4000000000L, new Date().getTime()));
start = new Date();
System.out.println("if(a) - a always false - condition on long");
System.out.println(timeBasicL(2000000000, start.getTime(), start.getTime() - 4000000000L));
start = new Date();
System.out.println("if(a && b) - a always false, a and and b both conditions on long");
System.out.println(timeAdvL(2000000000, start.getTime(), start.getTime() - 4000000000L, new Date().getTime()));
start = new Date();
System.out.println("if(a && b) - a always false, b always true");
System.out.println(timeAdv(2000000000, start, start.getTime() - 4000000000L, new Date()));
start = new Date();
System.out.println("if(a && b) - both true");
System.out.println(timeAdv(2000000000, start, start.getTime() + 1, new Date(start.getTime() + 4000000000L)));
start = new Date();
System.out.println("if(a && b) - a always true, b always false");
System.out.println(timeAdv(2000000000, start, new Date(start.getTime() + 4000000001L).getTime(), new Date(start.getTime() + 4000000000L)));
}
private static int timeBasic(int size, Date start, long l) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
Date date = new Date(l++);
if (start.before(date)) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeAdv(int size, Date start, long l, Date end) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
Date date = new Date(l++);
if (start.before(date) && end.after(date)) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeAdv2(int size, Date start, long l, long end) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
Date date = new Date(l++);
if (start.before(date) && end > l) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeBasicL(int size, long start, long l) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
l++;
if (start < l) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
private static int timeAdvL(int size, long start, long l, long end) {
long begin = System.currentTimeMillis();
int c = 0;
for (int i = 0; i < size; i++) {
l++;
if (start < l && end > l) {
c++;
}
}
System.out.println(System.currentTimeMillis() - begin);
return c;
}
}
JVM以一种方式优化您的代码,在第一种情况下,
start.before(date)
根本不会被计算(我认为)。尝试使用-Djava.compiler=NONE运行它,并查看结果。当您运行的代码没有任何用处时,您取决于JIT可以消除或不消除什么。在您的情况下,代码似乎正在被删除
在快速情况下,每个循环需要0.32纳秒,这太短了,不现实。i、 e.大约一个时钟周期。
较慢的情况是3.6纳秒,这更为现实,但这可能意味着它只是大部分优化了
当您将行为从always false切换到always true,反之亦然时,必须对代码进行重新优化,并且您可能正在计时检测和替换代码所需的时间,而不是实际执行所需的时间
我建议您添加一个外部循环来运行main()中的所有代码三次,您应该会看到一个甚至更大的差异。用Java编写有意义的微基准测试是很困难的。是吗?如果没有,那么现在就回去做吧!如果你使用现有的框架,这可能会更容易。使用分析工具,你会得到更好的结果。如果您正在使用eclipse,请尝试:@TheBronx:我不认为剖析器可以替代编写好的微基准。@JoachimSuer使用剖析器,您可以看到引擎盖下发生的事情(调用数量、消耗资源的方法…)。我想那也会有帮助。不是用micro bench代替,我认为两者都很有用。你似乎是对的,我用-Djava.compiler=NONE运行,然后时间差消失了。我假设我在循环中重新初始化了日期这一事实足以确保它没有得到优化,但显然没有。谢谢您的回答。-Djava.compiler=NONE
禁用编译器,因此其结果对于实际生产使用来说绝对没有意义。是的,但也会关闭优化,因此您可以看到这不是一个&&运算符问题。
if(a) - a always false
640
0
if(a && b) - a always false, a and b both date method
7079
0
if(a && b) - a always false, b is condition on longs not date
710
0
if(a) - a always false - condition on long
639
0
if(a && b) - a always false, a and and b both conditions on long
708
0
if(a && b) - a always false, b always true
6873
0
if(a && b) - both true
11995
2000000000
if(a && b) - a always true, b always false
13746
0