【问题标题】:ArrayList shows different time of execution each time why?ArrayList 每次显示不同的执行时间,为什么?
【发布时间】:2013-08-12 17:41:01
【问题描述】:

我正在使用ArrayList 并尝试在ArrayList 的开头添加new object 的预填充ArrayList,并准备好3000000 记录。

据我所知,它将在第一个索引处添加新对象并将下面的所有记录移动到它们之前的位置。每次我将新对象添加到该数组列表时都会发生这种情况。意味着执行时间应该相同(可能会发生一些变化)。

但是当我添加新记录时,它会显示 0 和某个时间 15。

这是我的程序

package com.rais;

import java.util.ArrayList;
import java.util.List;

public class ArrayListTest {

    public static List<String> arrList = new ArrayList<String>();
    static {
        for (int i = 0; i < 3000000; i++) {
            arrList.add("Hello"+i);
        }
    }


    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {

            long startTime = System.currentTimeMillis();

            arrList.add(0,"Rais"+i);

            long endTime = System.currentTimeMillis();
            System.out.println("Total execution time ="+(endTime-startTime));


        }
       }

    }

这是该程序的输出。

Total execution time =0
Total execution time =0
Total execution time =15
Total execution time =0
Total execution time =0

我很困惑为什么它显示 0 。每次应该显示 15 或接近 15,但不应该显示 0。

【问题讨论】:

  • 在某些旧版本的 Windows 上,此计时器的分辨率很差。我建议您使用 System.nanoTime() 并且由于代码在运行 10,000 次之前不会预热,因此我将忽略前 12,000 次运行。

标签: java performance collections arraylist indexing


【解决方案1】:

问题可能出在您的测量方式上,来自currentTimeMillis() 的文档;

以毫秒为单位返回当前时间。请注意,虽然返回值的时间单位是毫秒,但值的粒度取决于底层操作系统,可能更大。例如,许多操作系统以几十毫秒为单位测量时间。

换句话说,如果 currentTimeMillis 在您的系统上具有接近 15 毫秒的粒度,您将获得 0 或 15 毫秒,这取决于开始时间,即使操作总是花费相同的时间,也会略微随机。

【讨论】:

  • 请多解释一下。
  • @RaisAlam 简而言之,您系统上的currentTimeMillis 似乎每 15 毫秒增加 15,而不是每毫秒增加 1。如果你最终在它增加之前开始你的工作,即使是很短的时间也会看起来像 15 毫秒。例如,如果它增加了 14 毫秒,然后你开始工作需要 2 毫秒,currentTimeMillis() 将在你的工作中间增加 15,让 currentTimeMillis 告诉你你的工作花了 15 毫秒,即使它只花了 2 毫秒。如果您想要准确计时,则需要多次运行您的工作(例如 1000 次)并取平均值。
【解决方案2】:

我无法解释您看到的结果,但我怀疑它们至少部分是由您编写的过于简单的基准测试代码造成的。

高质量的基准测试代码可以运行数百或数千次迭代,并且对重新编译和运行时优化导致的性能变化很敏感。一般来说System.nanoTime()也用于这些计算。

请参阅 this excellent article from IBM,它解释了如何以稳健的方式进行基准测试。本文最后介绍了一个可用于根据最佳实践执行基准测试的框架。

【讨论】:

    【解决方案3】:

    正如其他答案中提到的,这可能是时钟粒度的问题。您可以使用以下代码检查是否是这种情况:

    public static void main(String[] args) {
        try {
            for (int i = 0; i < 30; i++) {
    
                long startTimeMillis = System.currentTimeMillis();
                long startTimeNanos = System.nanoTime();
    
                Thread.sleep(11);
    
                long endTimeMillis = System.currentTimeMillis();
                long endTimeNanos = System.nanoTime();
                System.out.println("Total execution time ="
                    + (endTimeMillis-startTimeMillis)+" ms / "
                    + (endTimeNanos-startTimeNanos)+" ns");
            }
    
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    

    另一种(不太可能)的可能性是 ArrayList 中的数组已达到容量,并且正在扩展(被更大的数组替换)。

    【讨论】:

      【解决方案4】:

      您没有得到准确时间的原因很可能是因为 currentTimeMillis() 不够精确,无法测量它。循环 10000 个并计时,看看你得到了什么。添加到 ArrayList 可能需要微秒,而不是毫秒(在通常情况下)。您看到的 15 毫秒可能是由于垃圾收集或其他原因造成的延迟 - 但无论如何,您的采样太小而无法获得准确的结果。

      【讨论】:

      • 同意数据很小,但是在添加新对象后,它会将之前添加的 299999 对象移动到之前的位置,我想这需要时间,我们可以以毫秒为单位计算它们
      • 明白了——你说得有道理——我第一次读错了代码,没有听懂。我仍然建议增加你正在做的事情的数量,直到它更可衡量。
      • 增加更多会导致内存不足异常。让我尝试增加堆内存。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-01
      • 2017-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-12
      • 1970-01-01
      相关资源
      最近更新 更多