Хэш-карта против производительности массива - PullRequest
20 голосов
/ 24 июня 2011

Является ли (с точки зрения производительности) лучше использовать массивы или HashMaps, когда известны индексы массива?Имейте в виду, что «массив / карта объектов» в этом примере является лишь примером, в моем реальном проекте он генерируется другим классом, поэтому я не могу использовать отдельные переменные.

ArrayExample:

SomeObject[] objects = new SomeObject[2];
objects[0] = new SomeObject("Obj1");
objects[1] = new SomeObject("Obj2");

void doSomethingToObject(String Identifier){
    SomeObject object;
    if(Identifier.equals("Obj1")){
        object=objects[0];
    }else if(){
        object=objects[1];
    }
    //do stuff
}

HashMapExample:

HashMap objects = HashMap();
objects.put("Obj1",new SomeObject());
objects.put("Obj2",new SomeObject());

void doSomethingToObject(String Identifier){
    SomeObject object = (SomeObject) objects.get(Identifier);
    //do stuff
}

HashMap выглядит намного лучше, но мне действительно нужна производительность, так что он имеет приоритет.

РЕДАКТИРОВАТЬ: Ну, Array's itтогда, предложения все еще приветствуются

РЕДАКТИРОВАТЬ: Я забыл упомянуть, размер массива / HashMap всегда одинаков (6)

РЕДАКТИРОВАТЬ: Похоже, что HashMaps быстрее. Array: 128ms Hash: 103ms

При использовании меньшего количества циклов HashMaps был даже в два раза быстрее

тестовый код:

import java.util.HashMap;
import java.util.Random;

public class Optimizationsest {
private static Random r = new Random();

private static HashMap<String,SomeObject> hm = new HashMap<String,SomeObject>();
private static SomeObject[] o = new SomeObject[6];

private static String[] Indentifiers = {"Obj1","Obj2","Obj3","Obj4","Obj5","Obj6"};

private static int t = 1000000;

public static void main(String[] args){
    CreateHash();
    CreateArray();
    long loopTime = ProcessArray();
    long hashTime = ProcessHash();
    System.out.println("Array: " + loopTime + "ms");
    System.out.println("Hash: " + hashTime + "ms");
}

public static void CreateHash(){
    for(int i=0; i <= 5; i++){
        hm.put("Obj"+(i+1), new SomeObject());
    }
}

public static void CreateArray(){
    for(int i=0; i <= 5; i++){
        o[i]=new SomeObject();
    }
}

public static long ProcessArray(){
    StopWatch sw = new StopWatch();
    sw.start();
    for(int i = 1;i<=t;i++){
        checkArray(Indentifiers[r.nextInt(6)]);
    }
    sw.stop();
    return sw.getElapsedTime();
}



private static void checkArray(String Identifier) {
    SomeObject object;
    if(Identifier.equals("Obj1")){
        object=o[0];
    }else if(Identifier.equals("Obj2")){
        object=o[1];
    }else if(Identifier.equals("Obj3")){
        object=o[2];
    }else if(Identifier.equals("Obj4")){
        object=o[3];
    }else if(Identifier.equals("Obj5")){
        object=o[4];
    }else if(Identifier.equals("Obj6")){
        object=o[5];
    }else{
        object = new SomeObject();
    }
    object.kill();
}

public static long ProcessHash(){
    StopWatch sw = new StopWatch();
    sw.start();
    for(int i = 1;i<=t;i++){
        checkHash(Indentifiers[r.nextInt(6)]);
    }
    sw.stop();
    return sw.getElapsedTime();
}

private static void checkHash(String Identifier) {
    SomeObject object = (SomeObject) hm.get(Identifier);
    object.kill();
}

}

Ответы [ 7 ]

32 голосов
/ 24 июня 2011

HashMap использует массив внизу, поэтому он никогда не может быть быстрее, чем правильно использовать массив.

Random.nextInt() во много раз медленнее, чем то, что вы тестируете, даже использование массива для проверки массива приведет к искажению ваших результатов.

Причина, по которой ваш эталонный массив такой медленный, заключается в сравнении равных, а не в самом доступе к массиву.

HashTable обычно намного медленнее, чем HashMap, потому что он делает то же самое, но также синхронизируется.

Распространенная проблема с микро-бенчмарками - это JIT, который очень хорошо удаляет код, который ничего не делает. Если вы не будете осторожны, вы будете проверять, достаточно ли вы запутали JIT, чтобы он не мог тренироваться, ваш код ничего не делает.

Это одна из причин, по которой вы можете написать микропроцессоры, которые выполняют системы C ++. Это потому, что Java является более простым языком и его легче рассуждать и, таким образом, обнаруживать код, который не делает ничего полезного. Это может привести к тестам, которые показывают, что Java «ничего полезного» не делает намного быстрее, чем C ++;)

4 голосов
/ 24 июня 2011

массивы, когда известны индексы, быстрее (HashMap использует массив связанных списков за кулисами, что добавляет немного накладных расходов над обращениями к массиву, не говоря уже о операциях хеширования, которые необходимо выполнить)

и FYI HashMap<String,SomeObject> objects = HashMap<String,SomeObject>(); делает так, что вам не придется разыгрывать

2 голосов
/ 24 июня 2011

Логично, HashMap определенно подходит в вашем случае. С точки зрения производительности также выигрывает, так как в случае массивов вам нужно будет выполнить ряд сравнений строк (в вашем алгоритме), тогда как в HashMap вы просто используете хеш-код, если коэффициент загрузки не слишком высок. Размер массива и HashMap необходимо будет изменить, если вы добавите много элементов, но в случае HashMap вам также потребуется перераспределить элементы. В этом случае HashMap проигрывает.

2 голосов
/ 24 июня 2011

В показанном примере, я думаю, HashTable выигрывает.Проблема с массивом заключается в том, что он не масштабируется.Я предполагаю, что вы хотите иметь более двух записей в таблице, и дерево ветвей условия в doSomethingToObject быстро станет громоздким и медленным.

0 голосов
/ 19 апреля 2013

Пожалуйста, никогда, никогда не используйте расширенный if / else if / else if / else if / else if / else в подобных случаях. Причина, по которой я повторял это много раз, состоит в том, чтобы вы чувствовали себя так, как будто ваш Java-интерпретатор испытывает такие кодовые блоки.

Как только у вас будет более одного if, используйте либо hashmap, либо switch / case (java 7 позволит вам сделать это для Strings, а java 6 - использовать enum). Еще лучшим решением для проверки только для чтения является ImmutableMap из фреймворка, такого как guava; у них высоко оптимизированные операции чтения, поскольку они не разрешают запись.

0 голосов
/ 24 июня 2011

Пример странный. Основная проблема заключается в том, являются ли ваши данные динамическими. Если это так, вы не можете написать свою программу таким образом (как в случае с массивом). Другими словами, сравнение между вашим массивом и реализацией хэша не является справедливым. Реализация хеша работает для динамических данных, но реализация массива - нет.

Если у вас есть только статические данные (6 фиксированных объектов), массив или хэш просто работают как держатель данных. Вы даже можете определить статические объекты.

0 голосов
/ 24 июня 2011

Массивы обычно работают быстрее, чем классы коллекций.

PS. Вы упомянули HashTable в своем посте. HashTable имеет еще худшую производительность, чем HashMap. Полагаю, ваше упоминание о HashTable было опечаткой

"HashTable выглядит намного лучше "

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...