我有两段代码,我想知道哪些代码运行速度更快,为什么速度更快。我对JVM和CPU的了解较少,但我很努力。每个提示都会有所帮助。
int[] a=new int[1000];
int[] b=new int[10000000];
long start = System.currentTimeMillis();
//method 1
for(int i=0;i<1000;i++){
for(int j=0;j<10000000;j++){
a[i]++;
}
}
long end = System.currentTimeMillis();
System.out.println(end-start);
start=System.currentTimeMillis();
//method 2
for(int i=0 ;i<10000000;i++){
for(int j=0;j<1000;j++){
b[i]++;
}
}
end = System.currentTimeMillis();
System.out.println(end-start);
答案 0 :(得分:5)
<强>复杂性强>
就渐近复杂度(例如big-O表示法)而言,它们具有相同的运行时间。
数据本地化
暂时忽略任何优化......
b
更大,因此更有可能分割为多个(或更多)pages。因此,第一个可能更快。
这里的差异可能相当小,除非并非所有这些页面都适合RAM并需要写入磁盘(由于b
只有10000000 * 4 = 40000000字节= 38,因此不大可能MB)。
<强>优化强>
第一种方法涉及“执行a[i]++
10000000次”(对于固定的i
),理论上可以很容易地被优化器转换为a[i] += 10000000
。
b
可以进行类似的优化,但仅限b[i] += 1000
,仍需运行10000000次。
优化器可以自由地执行此操作或不执行此操作。据我所知,Java语言规范没有说明应该和不应该优化的内容,只要它不会改变最终结果。
作为一个极端的结果,理论上,优化器可以看到你在循环之后没有对a
或b
做任何事情,从而摆脱了两个循环。
答案 1 :(得分:5)
我会把答案放在那里,理论上它们将完全相同,但在实践中会有一个小的,但可以忽略不计的差异。实际上,实际上太小了。
基本思想是数组b
如何存储在内存中。因为它要大得多,取决于你的平台/实现,它可能存储在块中,也就是非连续的。这可能是因为1000万英寸的数组是4000万字节= 40 MB!
答案 2 :(得分:1)
第一个循环在我的系统上运行得更快(中位数:333毫秒对596毫秒)
(编辑:我在第一次回复中对数组访问次数做了错误的假设,请参阅注释)
后续增量(index ++)对同一数组的访问似乎比随机访问或减量(index--)访问更快。我假设 Java Hotspot编译器可以优化数组绑定检查,如果它识别出将逐步遍历该数组。
反转循环时,实际上运行速度较慢:
//incremental array index
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 10000000; j++) {
a[i]++;
}
}
//decremental array index
for (int i = 1000 - 1; i >= 0; i--) {
for (int j = 10000000 - 1; j >= 0; j--) {
a[i]++;
}
}
增量:349ms,减量:485ms。 没有边界检查,递减循环通常更快,特别是在旧处理器上(比较为零)。
如果我的假设是正确的,那么就会进行1000次优化边界检查而不是10000000次检查,因此第一种方法更快。
顺便说一句,在进行基准测试时:
System.nanoTime()
衡量时间增量。这样可以提供更准确的时间戳。 System.currentTimeMillis()
不是那么精确(取决于VM),并且通常在十几毫秒或更多毫秒的桶中“跳”,使得结果时间比实际更加不稳定。顺便说一下:1毫秒= 1'000'000纳秒。答案 3 :(得分:0)
我的猜测是它们几乎都是一样的。其中一个有一个较小的数组可以处理,但除了内存的初始分配之外没有太大的区别,这无论如何都在你的测量范围之外。
执行每次迭代的时间应该相同(将值写入数组)。递增较大的数字不应该使JVM比递增较小的数字更长,也不应该处理更小或更大的数组索引。
但为什么问题,如果你已经知道如何衡量自己?
答案 4 :(得分:0)
查看大符号
嵌套的for循环是O(n ^ 2) - 它们在理论上运行相同。
数字1000或100000是常数k O(n ^ 2 + k)
它们在实践中并不完全相同,因为其他各种各样的东西在起作用,但它会很接近。
答案 5 :(得分:0)
时间应该相等,结果显然会有所不同,因为a将包含1000个值为10000的条目,b将包含10000000个值为1000的条目。我真的不明白你的问题。最终开始的结果是什么? 可能是JVM将优化forloops,如果它理解最终结果将在数组中比最小数组更容易计算,因为它只需要1000个赋值,而另一个需要10 000倍以上
答案 6 :(得分:0)
首先是fuster。由于第一个a
和i
单元格的初始化次数要少得多。
答案 7 :(得分:0)
现代架构很复杂,所以回答这类问题绝非易事。
运行时间可能相同,或者第一次可能更快。
在这种情况下要考虑的事情主要是内存访问和优化。
一个好的优化器会意识到永远不会读取这些值,因此可以完全跳过循环,这两种情况下的运行时间都为0。此类优化可以在compile time或run-time进行。
如果没有优化,那么就需要考虑内存访问。 a[]
远小于b[]
,因此它更容易适应更快的缓存内存,因此cache misses更少。
另一件需要考虑的事情是memory interleaving。