java - 在JAVA的嵌套for循环中,为什么小循环中的大循环比大循环中的小循环更快?
问题描述
当迭代次数相同时,我想知道外部“for循环”的较小迭代是否更快。
这是我的java代码。
总循环迭代次数为 1000 亿次。
public class Test {
public static long run1() {
final long start = System.nanoTime();
long cnt = 0;
for(int i = 0; i<1000000000; i++) {
for(int j = 0 ; j<100 ; j++) {
cnt++;
}
}
final long end = System.nanoTime();
System.out.println("run1 : "+(end-start)*1e-9+" sec");
return start - end;
}
public static long run2() {
final long start = System.nanoTime();
long cnt = 0;
for(int i = 0; i<100; i++) {
for(int j = 0 ; j<1000000000 ; j++) {
cnt++;
}
}
final long end = System.nanoTime();
System.out.println("run2 : "+(end-start)*1e-9+" sec");
return start - end;
}
public static void main(String[] args) {
for(int i = 0 ; i < 10 ; i++) {
long test1 = run1();
long test2 = run2();
System.out.println("Time diff : "+(test1-test2)*1e-9+" sec\n");
}
}
}
这是结果
run1 : 4.5772473950000006 sec
run2 : 1.7155700900000002 sec
Time diff : -2.861677305 sec
run1 : 4.4107229420000005 sec
run2 : 1.6532413140000002 sec
Time diff : -2.7574816280000003 sec
run1 : 3.815836296 sec
run2 : 1.761153921 sec
Time diff : -2.054682375 sec
run1 : 3.913543021 sec
run2 : 1.752971717 sec
Time diff : -2.1605713040000003 sec
run1 : 3.851766485 sec
run2 : 1.7262416440000001 sec
Time diff : -2.1255248410000003 sec
run1 : 3.95305219 sec
run2 : 1.7323067330000002 sec
Time diff : -2.220745457 sec
run1 : 3.924869236 sec
run2 : 1.6953032440000002 sec
Time diff : -2.229565992 sec
run1 : 3.839871705 sec
run2 : 1.692300162 sec
Time diff : -2.147571543 sec
run1 : 3.93864626 sec
run2 : 1.704322469 sec
Time diff : -2.234323791 sec
run1 : 3.863758493 sec
run2 : 1.700392962 sec
Time diff : -2.163365531 sec
像这样,
我想知道为什么会出现这些结果。
并且,通过三重嵌套循环编辑,获得了类似的结果。
解决方案
简短的回答是:JIT 和你的数学是错误的。
让我们从你的运行方法开始,它以这个打印行和一个返回结束
System.out.println("run1 : "+(end-start)*1e-9+" sec");
return start - end;
这里的问题是您正在打印 end-start 并返回 start-end。我没有在运行方法中进行数学运算,而是将其转移,以便每次运行只负责运行和计时:
public class loops
{
public static long run1()
{
final long start = System.nanoTime();
long cnt = 0;
for (int i = 0; i < 1000000000; i++)
{
for (int j = 0; j < 100; j++)
{
cnt++;
}
}
final long end = System.nanoTime();
return end - start;
}
public static long run2()
{
final long start = System.nanoTime();
long cnt = 0;
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 1000000000; j++)
{
cnt++;
}
}
final long end = System.nanoTime();
return end - start;
}
public static void main(String[] args)
{
for (int i = 0; i < 10; i++)
{
long test1 = run1();
long test2 = run2();
System.out.println("run1 : " + test1 + " ns");
System.out.println("run2 : " + test2 + " ns");
System.out.println("Time diff : " + (test1 - test2) + " ns\n");
}
}
}
我还拿出了数学,因为……好吧,何必呢?将值视为纳秒有什么问题?原来是这样的...
运行此程序,您可以看到初始大值减小并接近零。在某些运行中,两个版本的它们甚至都达到零。
零纳秒?是的,即时计算。让量子计算吸吮它!好吧,这不是即时的。不是当您检查nanoTime 描述时:
此方法提供纳秒精度,但不一定提供纳秒分辨率(即值变化的频率)
它只是比可测量的要快,因为 JIT 可能最终发现该方法实际上并没有做任何事情。现在为什么一个或另一个比另一个下降得更快需要更深入地研究 JIT 以及它如何决定优化一种方法与另一种方法 - 这比我知道的要多。
最终,几乎没有区别。两种方法初次运行后,最大的时间差最多只有几毫秒。我不认为说一个版本真的比另一个版本快有什么意义。
推荐阅读
- python - 读取多个 CSV 文件并将它们添加到 pandas 数据框
- python-3.x - 如何根据特定条件将普通数据帧转换为 MultiIndex'd
- javascript - 验证字符是否可以用 Javascript 中的 windows-1250 编码
- javascript - 表单提交后运行页面
- java - 从文件夹中获取随机文件 - Java
- python - 在python中绘制正弦波时的问题
- python-3.x - 如何在python中使用欧几里得距离进行人脸识别
- django - Django:依赖项引用已安装应用程序的不存在的父节点
- outlook - Outlook-Redemption - RDOFolder.Items ItemAdd 事件未在联机模式下使用 Exchange 定期触发
- android - 无法确定应用程序 ID:com.android.tools.idea.run.ApkProvisionException