Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.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 为什么通过LinkedList的迭代速度很慢?_Java_Performance_List - Fatal编程技术网

Java 为什么通过LinkedList的迭代速度很慢?

Java 为什么通过LinkedList的迭代速度很慢?,java,performance,list,Java,Performance,List,爪哇8 我有一个相当大的集合(大约100万个元素),我需要遍历它并执行一些操作。有两种选择: 迭代一次并完成整个工作(这会使代码变得非常复杂) 迭代两次,在第一次迭代中完成一半工作,在第二次迭代中完成其余工作(这将大大简化代码) 因此,我认为迭代并不昂贵,并编写了一个简单的示例来衡量它(我不经常编写基准测试,因此它可能看起来有点傻): Collection col=newlinkedlist(); 对于(int i=0;i有很多的去装箱/装箱正在发生,这确实对性能有影响。 但除此之外,你必须知道

爪哇8

我有一个相当大的集合(大约100万个元素),我需要遍历它并执行一些操作。有两种选择:

  • 迭代一次并完成整个工作(这会使代码变得非常复杂)

  • 迭代两次,在第一次迭代中完成一半工作,在第二次迭代中完成其余工作(这将大大简化代码)

  • 因此,我认为迭代并不昂贵,并编写了一个简单的示例来衡量它(我不经常编写基准测试,因此它可能看起来有点傻):

    Collection col=newlinkedlist();
    对于(int i=0;i<30000000;i++){
    col.add(数学sqrt(i+1));
    }
    long start1=System.nanoTime();
    双精度=0.0;
    for(双d:col){
    res+=d+d;
    }
    long-end1=System.nanoTime();
    System.out.println(end1-start1);
    System.out.println(“=======================================================”);
    long start2=System.nanoTime();
    双res2=0.0;
    for(双d:col){
    res2+=d;
    }
    for(双d:col){
    res2+=d;
    }
    long-end2=System.nanoTime();
    System.out.println(end2-start2);
    
    平均结果如下:

    1107881047

    2133450162
    秒(速度慢一倍)


    所以,迭代是一个相当缓慢的过程。但我不明白为什么?我认为我们做的工作量几乎相同,所以表现会有很大不同

    值得注意的是,如果我使用
    ArrayList
    而不是链表,结果是:

    3858616604

    422297749
    Second(比第一个快十倍,比上例快两倍)


    你不能简单地解释一下这种性能差异吗?

    我认为有几个原因导致了你所看到的性能下降

  • 自动装箱
  • 算法
  • 自动装箱 每次您获取一个基元类型(例如,
    int
    float
    等)并将其放入其等价类(即,
    Integer
    float
    等)时,基元值都会被装箱。当需要将其用作基本体时,需要将其取消装箱。这里的要点是这样做需要CPU周期和时间

    可以提供有关自动装箱的更多详细信息

    算法 简单地说,您使用的只在列表上迭代一次的算法是
    O(n)
    ,而您使用的需要两次迭代的实现现在是
    O(2n)
    。两者仍然是O(n),但都知道Big-O是一个渐近上界,而不是“性能”的度量。应该仍然清楚的是,在同一个列表上迭代两次所需的工作量大约是仅在该列表上迭代一次所需工作量的两倍

    算法和自动装箱相结合产生了显著的效果,您可以在如下代码中看到:

    for(int i = 0; i < reallyLargeNumberHere; i++){
        col.add(Math.sqrt(i + 1));
    }
    
    for(int i=0;i
    sqrt
    计算本身很昂贵,需要进行自动装箱来添加每个元素。尽管如此,对大型列表的双重迭代将是罪魁祸首

    简言之
  • 您在一个大集合上进行迭代,在第二个实现中执行了两次;您现在必须支付两次
    O(n)
    罚款
  • 你正在遭受自动拳击造成的打击
  • sqrt
    算法本身速度很慢
  • 在添加/删除节点时,链表实现是
    O(1)
    ,但对于迭代/搜索则不是这样——它们往往是
    O(n)
  • 链表对CPU缓存不友好,因为它们不像基本数组那样分配在连续的内存块中
  • 第5点是关于CPU缓存其认为您将要使用的内容的能力,但由于数据位于内存的不同区域,因此这项工作的成本更高,而且不太可能按预期提高性能。(当阅读有关CPU管道和缓存命中/未命中的内容时,将与此相关。)

    了解您的程序在大多数情况下将执行的操作非常重要,这样您就可以选择合适的数据结构和算法进行匹配。不匹配的数据结构和算法将使您容易避免性能问题

    这可能会有帮助


    <>最后,对于简单的目的,使用<代码> Stase.NimeTime/Cord>可能是OK,如果你想做更严肃的事情,你应该考虑使用一个专门设计的工具来测试代码。

    < P>有很多的去装箱/装箱正在发生,这确实对性能有影响。 但除此之外,你必须知道数组和链表之间的区别

    在阵列中,为阵列分配一个连续的内存块。因此,元素的随机访问是可能的

    所以当我想得到一个大数组的第5000个元素时,它会在瞬间返回它

    时间复杂性

    访问元素=O(1)

    但在链表中,不能随机访问元素。要访问某个元素,您需要遍历链表,直到找到所需的元素

    所以,如果我访问第三个元素,在内部它会像 1->2->3,返回第三个元素

    第一个元素没有关于第三个元素的任何信息,它只有到第二个元素的链接

    时间复杂性

    访问元素=O(n)

    在决定使用哪种类型的集合时,您需要了解数据结构和时间复杂性的概念。因为在大型数据集中,它可能会导致巨大的性能差异

    您可以参考此链接了解时间复杂性:

    首先,对于基准测试,您最好使用

    现在,到
    for(int i = 0; i < reallyLargeNumberHere; i++){
        col.add(Math.sqrt(i + 1));
    }
    
    //First:
    for(Double d : col){
        res += d + d;
    }
    
    //Second
    for(Double d : col){
        res2 += d;
    }
    for(Double d : col){
        res2 += d;
    }
    
    LinkedList<String> linkedList = new LinkedList<String>();
    linkedList.add("eBay");
    linkedList.add("Paypal");
    linkedList.add("Google");
    linkedList.add("Yahoo");
    linkedList.add("IBM");
    linkedList.add("Facebook");
    // ListIterator approach
    System.out.println("ListIterator Approach: ");
    ListIterator<String> listIterator = linkedList.listIterator();
    while (listIterator.hasNext()) {
        System.out.println(listIterator.next());
    }