Java迭代HashTable与ArrayList速度

发布于 2024-12-21 15:12:51 字数 383 浏览 1 评论 0原文

我正在编写一个简单的 3D SW 渲染引擎。我有一个包含整个场景的默认 ArrayList。现在,我希望能够按名称添加、删除和选择对象,就像 3D 编辑器所做的那样(因为它比鼠标选择简单得多,但在家庭作业中仍然看起来不错:))。

因此,我首先想到的是使用 Hashtable 作为场景 ArrayList 的名称和索引。但是,后来我想我可以直接使用 Hashtable 保存场景,然后使用迭代器遍历它进行渲染。

所以我想问一下,在3D引擎中,什么是速度优先?因为与选择对象相比,我每秒会多次循环场景。 ArrayList迭代哈希表 快吗?谢谢。

I am writing a simple 3D SW rendering engine. I have a default ArrayList<Object3D> containing the whole scene. Now, I want to be able to add, remove and select objects by name, like 3D editors do (because its MUCH more simple than mouse select, but still looking good in homework :) ).

So, the first thing I thought is to have Hashtable for name and index to scene ArrayList. But, then I thought I could just simply save the scene using Hashtable directly, and go through it to render using iterator.

So I want to ask, in a 3D engine, what is speed-preferable? Because I will for-loop the scene many times per second, compared to selecting object. Is ArrayList any faster than iterated Hashtable? Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

魂归处 2024-12-28 15:12:51

首先,我建议您使用 HashMap 而不是 Hashtable,同样的原因,ArrayList 是比 Vector 更好的选择:由于无用的同步而导致的开销更少。

我的猜测是,迭代 ArrayList 比迭代 Hashtable(或 HashMap)返回的 Set 更快。 /code> 的) 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 比 HashMap 取得了巨大的胜利(3-4 倍),至少对于我迭代 HashMap 的风格来说是这样。我怀疑数组迭代器比数组下标慢的原因是所有迭代器对象都需要创建然后进行垃圾收集。

作为参考,这是在具有大量可用内存的 Intel 1.6GHz 四核 Windows 计算机上使用 Java 1.6.0_26(64 位 JVM)完成的。

First, I suggest you use a HashMap instead of a Hashtable, for the same reason that ArrayList is a better choice than a Vector: less overhead due to useless synchronization.

My guess is that iterating through an ArrayList will be faster than iterating through the Set returned by a Hashtable's (or HashMap's) entrySet() method. But the only way to know is to profile.

Obviously, changes to the display list (other than appending or chopping off the last element) are going to be faster for a HashMap than for an ArrayList.

EDIT
So I followed my own advice and benchmarked. Here's the code I used:

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

And here are the results for a typical run:

t1 time: 41412897
t2 time: 30580187
t3 time: 146536728

Clearly using an ArrayList is a big win (by a factor of 3-4) over a HashMap, at least for my style of iterating through a HashMap. I suspect the reason the array iterator is slower than array subscripting is all the iterator objects that need to be created and then garbage-collected.

For reference, this was done with Java 1.6.0_26 (64-bit JVM) on an Intel 1.6GHz quad-core Windows machine with plenty of free memory.

甜`诱少女 2024-12-28 15:12:51

我相当确定迭代ArrayList会比迭代Hashtable更快。不过,不确定差异有多大——在实际的内部逻辑中可能是(拇指吸)2 倍,但这并不多。

但请注意,除非需要多线程同步,否则应该使用 HashMap 而不是 Hashtable。在那里可以获得一些性能。

I'm fairly sure that iterating through the ArrayList will be faster than iterating over the Hashtable. Not sure how significant the difference is, though -- maybe (thumb suck) 2x in the actual internal logic, but that's not much.

But note that, unless you need multithread synchronization, you should use a HashMap rather than a Hashtable. There's some performance to be gained there.

猫腻 2024-12-28 15:12:51

实际上,我查看了当前的 HashMap 实现(正如大家指出的那样,优于 Hashtable)。迭代值看起来就像简单地迭代底层数组。

因此,速度可能与迭代 ArrayList 相当,尽管可能需要一些时间跳过 HashMap 底层数组中的间隙。

总而言之,分析为王。

Actually, I looked at the current HashMap implementation (preferred over Hashtable as everyone points out). Iterating over the values looks like it's simply iterating through an underlying array.

So, speed will probably be comparable to iterating an ArrayList, though there may be some time skipping over gaps in the HashMaps underlying array.

All said, profiling is king.

听你说爱我 2024-12-28 15:12:51

A) 不要使用Hashtable,使用HashMapHashtable 已被非正式弃用

B) 这取决于应用程序。在 HashMap 中查找速度会更快,迭代可能会相同,因为两者都在内部使用数组。 (但是 HashMap 中的数组有间隙,因此这可能会给 ArrayList 带来一些优势)。哦,如果你想保持固定的迭代顺序,请使用 LinkedHashMap (按插入排序)或 TreeMap (按自然顺序排序)

A) don't use Hashtable, use HashMap. Hashtable is informally deprecated

B) That depends on the application. Lookup will be faster in the HashMap, Iteration will likely be the same as both use arrays internally. (but the arrays in a HashMap have gaps, so that might give a slight advantage to the ArrayList). Oh, and if you want to maintain a fixed order of iteration, use LinkedHashMap (sorted by insertion) or TreeMap (sorted by natural ordering)

醉态萌生 2024-12-28 15:12:51

正如已经说过的,最好使用HashMap。关于迭代,理论上,ArrayList 必须更快,原因有两个。首先,数据结构更简单,访问时间更少。第二个是 ArrayList 可以通过索引进行迭代,而无需创建 Iterator 对象,在大量使用的情况下,产生的垃圾更少,因此 gc 也更少。
在实践中 - 您可能不会注意到差异,这取决于您要使用它的重量。

As already said, it's better to use HashMap. Regarding to iteration, in theory, ArrayList has to be faster for two reasons. First is that data structure is simpler, which gives less access time. The second is that ArrayList can be iterated by index without creating Iterator object, which, in case of intense use, produce less garbage and therefore less gc.
In practice - you may not notice difference, depends how heavy you are going to use it.

节枝 2024-12-28 15:12:51

如果不需要检索同步,请使用 java.util.HashMap 而不是 java.util.Hashtable

Use java.util.HashMap instead of java.util.Hashtable if you don't need retrieval synchronization.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文