Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 哪种代码运行得更快?_Java_Performance - Fatal编程技术网

Java 哪种代码运行得更快?

Java 哪种代码运行得更快?,java,performance,Java,Performance,我有两段代码,我想知道它们运行时哪个更快,为什么更快。我对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]++; } }

我有两段代码,我想知道它们运行时哪个更快,为什么更快。我对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);
int[]a=新的int[1000];
int[]b=新int[10000000];
长启动=System.currentTimeMillis();
//方法1

对于(int i=0;i我的猜测是,它们的数组几乎相同。其中一个要处理的数组较小,但除了内存的初始分配之外,这没有多大区别,因为内存的初始分配超出了您的测量范围

执行每个迭代的时间应该相同(将值写入数组)。增加较大的数字不会比增加较小的数字花费JVM更长的时间,也不应该寻址较小或较大的数组索引


但是,如果你已经知道如何测量自己,为什么还要问这个问题呢?

看看大oh符号

嵌套的for循环是O(n^2)-理论上它们将运行相同的循环

1000或100000是一个常数ko(n^2+k)


它们在实践中并不完全相同,因为其他因素在起作用,但它们会很接近。

时间应该相等,结果显然会不同,因为a将包含1000个值为10000的条目,b将包含10000000个值为1000的条目。我真的不明白你的问题。结束-开始的结果是什么?
如果JVM了解数组中的最终结果,那么它可能会优化forloops,而最小的数组将更容易计算,因为它只需要1000个赋值,而另一个需要10000倍以上的复杂度。

就渐近复杂性而言(例如,大O表示法),它们具有相同的运行时间

数据本地化

暂时忽略任何优化

b
更大,因此更可能被拆分为多个(或多个)。因此,第一个可能更快

这里的差异可能相当小,除非不是所有这些页面都适合RAM,并且需要写入磁盘(这在这里不太可能,因为
b
只有10000000*4=40000000字节=38MB)

优化

第一种方法涉及“执行
a[i]+
10000000次”(对于固定的
i
),理论上可以很容易地由优化器转换为
a[i]+=10000000

类似的优化可以针对
b
,但仅针对
b[i]+=1000
,这仍然需要运行10000000次

优化器可以自由地做这件事,也可以不做这件事。据我所知,Java语言规范没有太多关于应该和不应该优化的内容,只要它不改变最终结果


作为一个极端的结果,优化器可以在理论上看到,在循环之后,你没有使用
a
b
做任何事情,从而消除两个循环。

我将在这里给出我的答案,理论上它们完全相同,但实际上会有一个很小但可以忽略的差异。太小了,根本不重要,事实上

基本思想是数组
b
如何存储在内存中。因为它要大得多,根据您的平台/实现,它可能存储在块中,也称为非连续。这可能是因为1000万整数的数组是4000万字节=40 MB


编辑:我分别得到572和593。

第一个将更模糊。因为第一个
a
I
单元格的初始化次数要少得多。

第一个循环在我的系统上运行得更快(中位数:333 ms vs.596 ms)
(编辑:我在第一次响应中错误地假设了数组访问的数量,请参见注释)

与随机访问或递减(索引--)访问相比,对同一数组的后续增量(索引++)访问似乎要更快。我假设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]++;
    }
}
//增量数组索引
对于(int i=0;i<1000;i++){
对于(int j=0;j<10000000;j++){
a[i]++;
}
}
//递减数组索引
对于(int i=1000-1;i>=0;i--){
对于(int j=10000000-1;j>=0;j--){
a[i]++;
}
}
递增:349ms,递减:485ms。 如果没有边界检查,递减循环通常更快,尤其是在旧处理器上(与零相比)

如果我的假设是正确的,这将进行1000次优化边界检查,而不是10000000次检查,因此第一种方法更快

顺便说一下,在进行基准测试时:

  • 进行多轮比较平均值/中等值而不是第一个样本
  • 在Java中:给你的基准测试一个预热阶段(在测量之前执行几次)。在第一次运行时,必须加载类,并且在热点VM特性启动并执行本机编译之前,可能会解释代码
  • 使用
    System.nanoTime()
    测量时间增量。这将提供更精确的时间戳
    System。currentTimeMillis()
    没有那么精确(取决于VM),通常以十几毫秒或更长的时间“跳跃”,使结果的波动性比实际波动性大几倍。顺便说一句:1毫秒=1'000'000纳秒

    • 现代建筑是复杂的,所以回答这类问题绝非易事

      运行时间可以相同,也可以更快

      这种情况下要考虑的主要是内存访问和优化。 一个好的优化器会意识到这些值永远不会被读取,因此循环可以被读取