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

我有一个程序,它从数据库(使用Hibernate)获取记录,并填补他们在一个Vector 。 有关于操作的性能的一个问题和我与所述一个测试Vector由一个替换HashSet 有了30万的记录,速度增益是巨大的 - 45分钟至2分钟!

所以我的问题是,是什么原因造成这种巨大的差异? 难道仅仅是一点,在所有方法Vector同步或内部点Vector使用数组,而HashSet不? 或者是其他东西?

代码运行在单个线程。

编辑:该代码仅在插入值Vector (而在其他情况下HashSet )。

--------------解决方案-------------

如果它试图利用Vector 为一组 ,并将其添加,然后填充矢量前检查记录的存在,成为一个为O(n ^ 2)操作,具有O(n)的比较HashSet 。 它也将成为一个为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");
}
}

输出:

拍摄时间:38ms

现在很明显这不会是非常准确- System.currentTimeMillis是没有得到准确计时的最好方法-但它显然不是服用45分钟。 换句话说,你应该看看其他地方的问题, 如果你真的只是调用Vector.add(item)

现在,改变上述代码用

vector.add(0, "dummy value"); // Insert item at the beginning

使一个巨大的差异-它经过42 秒钟 ,而不是38ms。 这显然​​差了很多 - 但它仍然被45分钟长的路要走 - 我怀疑我的桌面是60倍的速度你的。

如果你是在中间插入他们或开始而不是在年底,那么矢量需要将它们全部沿。 每一次插入。 HashMap的,而另一方面,并​​不真正关心或做任何事情。

矢量已经过时,不应再使用。 与ArrayList的或LinkedList的个人资料(取决于你如何使用列表),你会看到其中的差别(同步VS UNSYNC)。 你为什么要使用一个单线程应用向量呢?

矢量默认情况下同步; HashSet中是没有的。 这是我的猜测。 获得监视器的访问需要时间。

我不知道是否有读取测试,但Vector和HashSet的均为O(1)如果get()用于访问向量项。

在正常情况下, 是完全不合理的那个插入300000记录到一个Vector将需要43分钟长于插入相同的记录插入HashSet

不过,我觉得有一种可能什么一个可能的解释。

首先,走出了数据库的记录必须有重复的比例相当高。 或者至少,他们根据你的记录类的等于/ hashCode方法的语义必须是重复的。

接下来,我想你一定要推非常接近填满堆。

使得其原因HashSet溶液是如此之快的是,它是大多数记录被替换为 set.add操作。 相比之下, Vector解决方案是保持所有的记录,和JVM花费其大部分时间要挤,去年0.05%超过,和遍地运行GC的内存。

测试这种理论的一种方式是运行该Vector与一个更大的堆版本的应用程序。



不管,探讨这类问题的最好方法是运行使用分析器的应用程序,看到所有的CPU时间是怎么回事。

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");
}
}

如果您检查重复的元素之前插入向量中的元素,将需要更多的时间取决于向量的大小。 最好的办法是使用HashSet的高性能,高的Hashset因为不允许重复,也不需要插入之前先检查是否有重复的元素。

据亨氏Kabutz博士,他在简报中一说这一点。

老Vector类可以实现序列化的幼稚方式。 他们只是做了默认的序列化,这将写入整个Object[]作为-是到流。 因此,如果我们插入了一堆元素到列表中,然后将其清除,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();
}
}

当我们运行这段代码,我们得到以下的输出:

LinkedList used 107 bytes
ArrayList used 117 bytes
Vector used 1310926 bytes

矢量可以使用的字节数量惊人正在连载的时候。 这里的教训? 千万不要使用向量列出的是序列化对象。 灾难的可能性实在太大了。

分类:java的 时间:2015-03-14 人气:0
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.830 (s). 10 q(s)