我正在编写一个简单的3D SW渲染引擎。我有一个包含整个场景的默认ArrayList<Object3D>
。现在,我希望能够按名称添加,删除和选择对象,就像3D编辑一样(因为它比鼠标选择更简单,但在家庭作业中仍然看起来很好:)。
所以,我想到的第一件事是Hashtable
为场景ArrayList
的名称和索引。但是,我认为我可以直接使用Hashtable
直接保存场景,然后使用迭代器进行渲染。
所以我想问一下,在3D引擎中,什么是速度优先?因为与选择对象相比,我将每秒多次循环场景。 ArrayList
是否比iterated Hashtable
更快?感谢。
答案 0 :(得分:6)
首先,我建议你使用HashMap
代替Hashtable
,原因与ArrayList
比Vector
更好的选择:由于无用的同步。
我的猜测是,迭代ArrayList
比迭代Set
(或Hashtable
'){{1}返回的HashMap
更快}} 方法。但要知道的唯一方法就是分析。
显然,entrySet()
对HashMap
的更改比ArrayList
的显示列表更改(除了追加或删除最后一个元素除外)。
修改强> 所以我遵循自己的建议和基准。这是我使用的代码:
import java.util.*;
public class IterTest {
static class Thing {
Thing(String name) { this.name = name; }
String name;
}
static class ArrayIterTest implements Runnable {
private final ArrayList<Thing> list;
ArrayIterTest(ArrayList<Thing> list) {
this.list = list;
}
public void run() {
int i = 0;
for (Thing thing : list) {
++i;
}
}
}
static class ArraySubscriptTest implements Runnable {
private final ArrayList<Thing> list;
ArraySubscriptTest(ArrayList<Thing> list) {
this.list = list;
}
public void run() {
int i = 0;
int n = list.size();
for (int j = 0; j < n; ++j) {
Thing thing = list.get(j);
++i;
}
}
}
static class MapIterTest implements Runnable {
private final Map<String, Thing> map;
MapIterTest(Map<String, Thing> map) {
this.map = map;
}
public void run() {
int i = 0;
Set<Map.Entry<String, Thing>> set = map.entrySet();
for (Map.Entry<String, Thing> entry : set) {
++i;
}
}
}
public static void main(String[] args) {
final int ITERS = 10000;
final Thing[] things = new Thing[1000];
for (int i = 0; i < things.length; ++i) {
things[i] = new Thing("thing " + i);
}
final ArrayList<Thing> arrayList = new ArrayList<Thing>();
Collections.addAll(arrayList, things);
final HashMap<String, Thing> hashMap = new HashMap<String, Thing>();
for (Thing thing : things) {
hashMap.put(thing.name, thing);
}
final ArrayIterTest t1 = new ArrayIterTest(arrayList);
final ArraySubscriptTest t2 = new ArraySubscriptTest(arrayList);
final MapIterTest t3 = new MapIterTest(hashMap);
System.out.println("t1 time: " + time(t1, ITERS));
System.out.println("t2 time: " + time(t2, ITERS));
System.out.println("t3 time: " + time(t3, ITERS));
}
private static long time(Runnable runnable, int iters) {
System.gc();
long start = System.nanoTime();
while (iters-- > 0) {
runnable.run();
}
return System.nanoTime() - start;
}
}
以下是典型运行的结果:
t1 time: 41412897
t2 time: 30580187
t3 time: 146536728
显然使用ArrayList是一个很大的胜利(比3-4倍),至少对于我通过HashMap迭代的风格而言。我怀疑数组迭代器比数组下标慢的原因是所有需要创建然后进行垃圾收集的迭代器对象。
作为参考,这是在Intel 1.6GHz四核Windows机器上使用Java 1.6.0_26(64位JVM)完成的,并且有足够的可用内存。
答案 1 :(得分:1)
我很确定迭代ArrayList
比迭代Hashtable
更快。不过不确定差异有多大 - 可能(拇指吮吸)2x在实际的内部逻辑中,但那并不多。
但请注意,除非您需要多线程同步,否则应使用HashMap
而不是Hashtable
。在那里可以获得一些表现。
答案 2 :(得分:0)
A)不要使用Hashtable
,请使用HashMap
。 Hashtable
已被非正式弃用
B)这取决于应用程序。查找在HashMap
中会更快,迭代可能与内部使用数组相同。 (但HashMap
中的数组有间隙,因此可能会给ArrayList
带来轻微优势。哦,如果你想维持一个固定的迭代顺序,可以使用LinkedHashMap
(按插入排序)或TreeMap
(按自然顺序排序)
答案 3 :(得分:0)
如果您不需要检索同步,请使用java.util.HashMap
代替java.util.Hashtable
。
答案 4 :(得分:0)
实际上,我查看了当前的HashMap
实施(首先是Hashtable
,因为每个人都指出)。迭代值似乎只是在底层数组中迭代。
因此,速度可能与迭代ArrayList
相当,但可能会有一些时间跳过HashMap
基础数组中的间隙。
所有人都说,剖析是王道。
答案 5 :(得分:0)
如前所述,最好使用HashMap
。关于迭代,理论上,ArrayList
必须更快,原因有两个。首先,数据结构更简单,访问时间更短。第二个是ArrayList
可以通过索引迭代而不创建Iterator对象,在强烈使用的情况下,产生的垃圾更少,因此gc更少。
在实践中 - 您可能没有注意到差异,取决于您将使用它的重量。