it-swarm.com.ru

Хэш-карта против производительности массива

Является ли (с точки зрения производительности) лучше использовать массивы или 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 выглядит намного лучше, но мне действительно нужна производительность, чтобы иметь приоритет.

Правка: Ну Массив это тогда, предложения по-прежнему приветствуются

Правка: Я забыл упомянуть, размер массива/HashMap всегда одинаков (6)

Правка: Похоже, что HashMaps быстрее Массив: 128 мс Хэш: 103 мс

При использовании меньшего количества циклов 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();
}

}

17
Tim

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

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

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

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

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

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

30
Peter Lawrey

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

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

4
ratchet freak

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

2
sehe

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

2
Alex Gitelman

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

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

0
Ajax

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

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

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

0
Basanth Roy

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

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

0
BlueGuitar