2011-12-14 6 views
4

나는 간단한 3D SW 렌더링 엔진을 작성 중이다. 전체 장면이 포함 된 기본값 인 ArrayList<Object3D>이 있습니다. 이제는 3D 편집기와 같이 이름으로 객체를 추가, 제거 및 선택할 수 있기를 원합니다 (마우스 선택보다 간단하지만 숙제가 여전히 좋기 때문에 :)).자바 반복 HashTable 대 ArrayList 속도

제가 생각하기에 가장 먼저 생각한 것은 ArrayList의 이름과 색인에 Hashtable이있는 것입니다. 그러나 그때 나는 단지 Hashtable을 사용하여 장면을 간단히 저장할 수 있고 iterator를 사용하여 렌더링 할 수 있다고 생각했습니다.

그래서 3D 엔진에서 속도가 더 좋은지 묻고 싶습니다. 왜냐하면 내가 객체를 선택하는 것에 비해 초당 여러 번 장면을 반복 할 것이기 때문입니다. iterated Hashtable보다 더 빠른 ArrayList이 있습니까? 감사. 때문에 쓸모 동기화에 적은 오버 헤드 :

답변

6

첫째, 난 당신이 ArrayListVector보다 더 나은 선택을하는 것과 같은 이유로, 대신 HashtableHashMap를 사용하는 것이 좋습니다.

제 추측은 ArrayList를 반복하는 단계 Hashtable 년대 (또는 HashMap 년대) entrySet() 메소드에 의해 리턴 된 Set 통해 반복보다 빠를 것입니다. 그러나 알 수있는 유일한 방법은 프로파일 링하는 것입니다.

분명히 디스플레이 목록을 변경하면 (마지막 요소를 추가하거나 잘라내는 것 외에) HashMapArrayList보다 빠릅니다.

편집 그래서 난 내 자신의 조언을 따라 벤치 마크.

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

그리고 여기에 일반적인 실행에 대한 결과 있습니다 : 분명히 ArrayList에를 사용하여

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

가 (3 ~ 4 배 정도) 큰 승리는 HashMap 이상 여기 내가 사용하는 코드는 적어도 HashMap을 통해 반복하는 스타일을 위해서. 배열 반복자가 배열 첨자보다 느린 이유는 생성되고 가비지 수집되어야하는 모든 반복자 개체 때문입니다.

메모리 크기가 많은 Intel 1.6GHz 쿼드 코어 Windows 컴퓨터에서 Java 1.6.0_26 (64 비트 JVM)을 사용하여이 작업을 수행했습니다.

+0

Absolutelyly answer, 큰 시간에 고마워. –

1

ArrayList을 통해 반복하는 것이 Hashtable을 반복하는 것보다 빠르다고 확신합니다. 차이가 얼마나 중요한지는 잘 모르겠지만 - 실제 내부 논리에서는 2 배가 될 수 있지만 그다지 중요하지 않습니다.

그러나 멀티 스레드 동기화가 필요하지 않으면 Hashtable 대신 HashMap을 사용해야합니다. 거기에 얻을 수있는 성능이 있습니다.

+1

동기화가 필요한 대부분의 응용 프로그램의 경우 Hashtable의 메서드 수준 동기화가 거의 항상 잘못되어 어쨌든 더 높은 수준의 동기화를 수행하게됩니다. 다중 스레드 동기화를 다루는 방법으로 Hashtable을 권장하지 않습니다. –

+0

Hashtable은 테이블이 다른 스레드에서 임의로 업데이트되는 경우에 유용합니다. 스레드와 반드시 "동기화"하고 싶지는 않지만 HashMap과 같은 손상된 테이블을 피하는 것만으로는되지 않습니다. –

+0

예, 내 의견에 "가장"밖에있는 경우입니다. 필자는 응용 프로그램이 스레드간에 맵을 공유해야하지만 맵이 손상되지 않도록 필요한 동기화 이외의 동기화가 필요하지는 않습니다. –

0

A) Hashtable을 사용하지 말고 HashMap을 사용하십시오. Hashtable은 비공식적으로 사용되지 않습니다.

B) 이는 애플리케이션에 따라 다릅니다. Lookup은 HashMap에서 더 빠를 것입니다. 반복은 내부적으로 배열을 사용하는 것과 같습니다. (그러나 HashMap의 배열에는 간격이 있으므로 ArrayList에 약간의 이점이 있음).아, 그리고 당신은 반복의 고정 된 질서를 유지하려는 경우 검색 동기화가 필요하지 않은 경우, (삽입으로 분류) LinkedHashMap 또는 TreeMap (자연 순서로 정렬)

0

사용 java.util.HashMap 대신 java.util.Hashtable를 사용합니다.

+1

아마도이 대답에 대해 좀 더 자세히 설명 할 수 있습니까? – NullUserException

0

사실, 현재 HashMap 구현 (모든 사람이 지적한대로 Hashtable보다 선호)을 보았습니다. 값을 반복하는 것은 단순히 기본 배열을 반복하는 것처럼 보입니다.

따라서 속도는 ArrayList을 반복하는 것과 비교할 수 있지만 HashMap 기본 배열의 간격을 건너 뛰는 데 약간의 시간이 걸릴 수 있습니다.

모두 프로파일 링은 왕이다.

+1

배열은 버킷의 배열입니다. 각 버킷에는 통과해야하는 항목 체인이 있습니다. 어쨌든 LinkedHashMap을 사용하여 순서를 유지해야하며 LinkedHashMap은 반복 할 배열이 아닌 일련의 항목을 사용합니다. –

0

이미 말했듯이 HashMap을 사용하는 것이 더 좋습니다. 반복과 관련하여, 이론적으로 ArrayList은 두 가지 이유로 더 빠르다. 첫째, 데이터 구조가 간단하여 액세스 시간이 적습니다. 두 번째는 ArrayList이 Iterator 객체를 생성하지 않고 인덱스에 의해 반복 될 수 있다는 것인데, 집중적 인 사용의 경우 더 적은 쓰레기를 생성하므로 gc가 적다. 실제로 - 차이를 느끼지 못할 수도 있습니다. 얼마나 무거울 지에 따라 다릅니다.