我是Java的新手,并且昨晚正在运行一些代码,这确实让我感到困扰。我当时正在构建一个简单的程序,以在for循环中显示每个X输出,当我将模数用作variable % variable
vs variable % 5000
或诸如此类时,我注意到性能的大幅下降。有人可以向我解释这是什么原因吗?这样我会更好...
这是“有效的”代码(很抱歉,如果我语法有点错误,我现在不在使用该代码的计算机上)
long startNum = 0;
long stopNum = 1000000000L;
for (long i = startNum; i <= stopNum; i++){
if (i % 50000 == 0) {
System.out.println(i);
}
}
这是“无效代码”
long startNum = 0;
long stopNum = 1000000000L;
long progressCheck = 50000;
for (long i = startNum; i <= stopNum; i++){
if (i % progressCheck == 0) {
System.out.println(i);
}
}
请注意,我有一个日期变量来衡量差异,一旦它变长了,第一个变量要花费50毫秒,而另一个变量要花费12秒或类似的时间。如果您的PC比我的PC效率更高或更低,您可能不得不增加stopNum
或降低progressCheck
。
我在网上寻找了这个问题,但找不到答案,也许我只是问的不对。
编辑:我没想到我的问题会如此受欢迎,我感谢所有答案。我确实在所花费的每个时间上进行了基准测试,效率低下的代码花费了更长的时间,即1/4秒vs. 10秒的付出或花费。尽管他们使用的是println,但是它们的用量相同,所以我不会想象这会造成很大的偏差,特别是因为差异是可重复的。至于答案,由于我是Java新手,所以我现在让投票决定哪个答案最好。我会在星期三之前选一个。
EDIT2:今晚我将进行另一个测试,在该测试中,代替模数,它只是增加一个变量,当它到达progressCheck时,它将执行一个测试,然后将该变量重置为0。
EDIT3.5:
我使用了此代码,下面将显示结果。.谢谢大家的出色帮助!我还尝试将long的short值与0进行比较,因此我的所有新检查都发生过“ 65536”次,从而使其重复次数相等。
public class Main {
public static void main(String[] args) {
long startNum = 0;
long stopNum = 1000000000L;
long progressCheck = 65536;
final long finalProgressCheck = 50000;
long date;
// using a fixed value
date = System.currentTimeMillis();
for (long i = startNum; i <= stopNum; i++) {
if (i % 65536 == 0) {
System.out.println(i);
}
}
long final1 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
//using a variable
for (long i = startNum; i <= stopNum; i++) {
if (i % progressCheck == 0) {
System.out.println(i);
}
}
long final2 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
// using a final declared variable
for (long i = startNum; i <= stopNum; i++) {
if (i % finalProgressCheck == 0) {
System.out.println(i);
}
}
long final3 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
// using increments to determine progressCheck
int increment = 0;
for (long i = startNum; i <= stopNum; i++) {
if (increment == 65536) {
System.out.println(i);
increment = 0;
}
increment++;
}
//using a short conversion
long final4 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
for (long i = startNum; i <= stopNum; i++) {
if ((short)i == 0) {
System.out.println(i);
}
}
long final5 = System.currentTimeMillis() - date;
System.out.println(
"\nfixed = " + final1 + " ms " + "\nvariable = " + final2 + " ms " + "\nfinal variable = " + final3 + " ms " + "\nincrement = " + final4 + " ms" + "\nShort Conversion = " + final5 + " ms");
}
}
结果:
- 固定= 874毫秒(通常为1000毫秒左右,但由于为2的幂,所以更快)
- 变量= 8590毫秒
- 最终变量= 1944毫秒(使用50000时约为1000毫秒)
- 增量= 1904 ms
- 短转换= 679毫秒
不足为奇的是,由于缺乏划分,短转换比“快速”方式快23%。这很有趣。如果您需要每256次(或大约256次)显示或比较某项内容,可以执行此操作,并使用
if ((byte)integer == 0) {'Perform progress check code here'}
一个最终的注意事项,在“最终声明的变量”上使用模数为65536(不是一个相当大的数字)的速度是固定值的一半(速度较慢)。它之前以相同的速度进行基准测试的地方。
final
在progressCheck
变量前面添加,则两者将再次以相同的速度运行。这使我相信,编译器或JIT在知道循环progressCheck
不变的情况下便设法优化循环。