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 Vector和HashSet之间的巨大性能差异_Java_Performance_Vector_Hashset - Fatal编程技术网

Java Vector和HashSet之间的巨大性能差异

Java Vector和HashSet之间的巨大性能差异,java,performance,vector,hashset,Java,Performance,Vector,Hashset,我有一个程序(使用Hibernate)从数据库中获取记录,并将它们填充到向量中。操作性能出现问题,我用HashSet替换了向量,进行了测试。有了300000条记录,速度提升是巨大的-45分钟到2分钟 所以我的问题是,是什么造成了如此巨大的差异?是因为Vector中的所有方法都是同步的,还是因为Vector内部使用数组而HashSet没有?还是别的什么 代码在单个线程中运行 编辑: 代码仅在向量(在另一种情况下,哈希集)中插入值。向量默认同步;哈希集不是。那是我的猜测。获取访问监视器需要时间 我不

我有一个程序(使用Hibernate)从数据库中获取记录,并将它们填充到
向量中。操作性能出现问题,我用
HashSet
替换了
向量
,进行了测试。有了300000条记录,速度提升是巨大的-45分钟到2分钟

所以我的问题是,是什么造成了如此巨大的差异?是因为
Vector
中的所有方法都是同步的,还是因为
Vector
内部使用数组而
HashSet
没有?还是别的什么

代码在单个线程中运行

编辑:
代码仅在
向量
(在另一种情况下,
哈希集
)中插入值。

向量默认同步;哈希集不是。那是我的猜测。获取访问监视器需要时间


我不知道您的测试中是否有读取,但是如果使用
get()
访问向量条目,那么Vector和HashSet都是O(1)

如果它试图将
向量
用作一个集合,并在添加它之前检查是否存在记录,那么填充向量就变成了一个O(n^2)操作,而
哈希集
则是O(n)。如果在向量的开头而不是结尾插入每个元素,那么它也将成为一个O(n^2)操作

如果您只是使用了
collection.add(item)
,那么我不希望看到这种区别——同步并没有那么慢

如果您可以尝试使用不同数量的记录对其进行测试,您可以看到每个版本是如何随着n的增加而增长的,这将使您更容易了解发生了什么

编辑:如果您只是使用
Vector.add
,则听起来可能发生了其他事情-例如,您的数据库在不同的测试运行中表现不同。下面是一个小测试应用程序:

import java.util.*;

public class Test {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    Vector<String> vector = new Vector<String>();
    for (int i = 0; i < 300000; i++) {
      vector.add("dummy value");
    }
    long end = System.currentTimeMillis();
    System.out.println("Time taken: " + (end - start) + "ms");
  }
}

这是一个巨大的区别——它需要42秒而不是38毫秒。这显然要糟糕得多——但距离45分钟还有很长的路要走——我怀疑我的桌面速度是你的60倍。

如果你在中间或开头插入它们,而不是在结尾,那么向量需要一直移动它们。每一个插页。另一方面,hashmap实际上并不关心或必须做任何事情。

向量已经过时,不应该再使用了。使用ArrayList或LinkedList配置文件(取决于您如何使用列表),您将看到差异(同步与不同步)。
为什么要在单线程应用程序中使用Vector?

在正常情况下,将300000条记录插入
Vector
比将相同的记录插入
哈希集中要花费43分钟的时间是完全不可信的

然而,我认为对可能发生的事情有一个可能的解释

首先,来自数据库的记录必须有很高比例的重复项。或者至少,根据记录类的equals/hashcode方法的语义,它们必须是重复的

下一步,我想你一定是快要填满这堆东西了

因此,
HashSet
解决方案速度更快的原因是大部分记录都被
set.add
操作替换。相比之下,
Vector
解决方案保留了所有记录,JVM花费了大部分时间试图通过反复运行GC来压缩最后
0.05%
的内存

测试这一理论的一种方法是使用更大的堆运行应用程序的
Vector
版本



不管怎样,调查此类问题的最佳方法是使用探查器运行应用程序,并查看所有CPU时间的去向。

根据Heinz Kabutz博士的说法,他在他的一篇文章中这样说

旧的Vector类以一种简单的方式实现序列化。它们只是执行默认序列化,将整个
对象[]
原样写入流中。因此,如果我们在列表中插入一组元素,然后清除它,Vector和ArrayList之间的差异是巨大的

import java.util.*;
import java.io.*;

public class VectorWritingSize {
  public static void main(String[] args) throws IOException {
    test(new LinkedList<String>());
    test(new ArrayList<String>());
    test(new Vector<String>());
  }

  public static void test(List<String> list) throws IOException {
    insertJunk(list);
    for (int i = 0; i < 10; i++) {
      list.add("hello world");
    }
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream out = new ObjectOutputStream(baos);
    out.writeObject(list);
    out.close();
    System.out.println(list.getClass().getSimpleName() +
        " used " + baos.toByteArray().length + " bytes");
  }

  private static void insertJunk(List<String> list) {
    for(int i = 0; i<1000 * 1000; i++) {
      list.add("junk");
    }
    list.clear();
  }
}
向量在序列化时可以使用惊人的字节数。这里的教训是什么永远不要在可序列化的对象中使用向量作为列表。灾难的可能性太大了。

导入java.util.*;
import java.util.*;

public class Test {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    Vector<String> vector = new Vector<String>();
    for (int i = 0; i < 300000; i++) {
       if(vector.contains(i)) {
         vector.add("dummy value");
       }
     }
    long end = System.currentTimeMillis();
    System.out.println("Time taken: " + (end - start) + "ms");
  }
}
公开课考试{ 公共静态void main(字符串[]args){ 长启动=System.currentTimeMillis(); 向量=新向量(); 对于(int i=0;i<300000;i++){ if(向量包含(i)){ 向量加上(“虚拟值”); } } long end=System.currentTimeMillis(); System.out.println(“所用时间:”+(结束-开始)+“毫秒”); } }

如果在向量中插入元素之前检查重复元素,则需要更多的时间,具体取决于向量的大小。最好的方法是使用HashSet实现高性能,因为HashSet不允许重复,并且在插入之前不需要检查重复元素。

如果看不到您对集合执行的操作,很难知道瓶颈在哪里。它们是不同的数据结构,因此,他们显然有不同的优势和劣势。使用最适合您需要的数据结构,如果数据结构的错误选择破坏了性能,请不要感到惊讶。但是正如@spender所说,在不知道你对这些数据结构实际做了什么的情况下,不可能说出为什么一个比另一个更快。编辑帖子以添加执行的操作-如果你能发布一些实际的代码,那会有所帮助。-1-对于@abhin4v来说,用明目张胆的谎言浪费我们的时间,比如“我只是调用
Vector.add
”。没有明确的唯一性检查。只是插入值。@abhin4v:如何插入值,例如
LinkedList used 107 bytes
ArrayList used 117 bytes
Vector used 1310926 bytes
import java.util.*;

public class Test {
  public static void main(String[] args) {
    long start = System.currentTimeMillis();
    Vector<String> vector = new Vector<String>();
    for (int i = 0; i < 300000; i++) {
       if(vector.contains(i)) {
         vector.add("dummy value");
       }
     }
    long end = System.currentTimeMillis();
    System.out.println("Time taken: " + (end - start) + "ms");
  }
}