2013-09-26 4 views
1

В настоящее время способ реализации хешей не реализуется. Я отслеживал работу в visualVM и видел, что слишком много времени процессора расходуется на MessageDigest. Вот код:Оптимизированный способ генерации большого количества хэшей

public static byte[] getHash(byte[] value) { 
     HashCode hashCode = hashFunction.newHasher().putBytes(value).hash(); 
     return hashCode.asBytes(); 
    } 

выше метод вызывается в цикле:

List<byte[]> someList; 
for(byte[] payload : someMap.values()) { 
      someList.add(getHash(payload)); 
     } 

В принципе, у меня есть map<SomeObject, byte[] payload) и мне нужно хэш отдельных значений и положить их в List<byte[]>. Я использую хешер guava, и карта ввода будет огромной. Что-нибудь я могу сделать лучше здесь? Причина, по которой мне нужно хэшировать все эти значения, заключается в том, что мне нужно хранить их в HBase.

EDIT алгоритм хэширования Я использую здесь MD5

+0

я бы искать более простой хэш, один, который работает непосредственно на массив байтов. Хэш-алгоритм, используемый в String, вероятно, довольно приличный: 's [0] * 31^(n-1) + s [1] * 31^(n-2) + ... + s [n-1]'. Если вы посмотрите на источник, алгоритм является простым для цикла с h = 31 * h + val [off ++]; 'inside ,. –

+1

Некоторые функции хэша будут работать быстрее - и никто не будет работать медленнее - если вы используете 'hashFunction.hashBytes (значение)' вместо 'hashFunction.newHasher(). PutBytes (value) .hash()'. –

ответ

1

Криптографически безопасный процесс хеширования очень ресурсоемкие, поэтому там очень мало вы могли бы сделать, чтобы оптимизировать свой код дальше. Я предполагаю, что невозможно сделать ваши массивы value значительно короче.

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

мне нужно выход заказываются

Одним из способов достижения этой цели будет сделать очередь пар {Integer, byte[]}, что на пары байт, которые будут хэшированным с их соответствующим индексом в списке вывода. Изменение размера списка someList upfront должно позволить вам не синхронизировать запись результатов обратно в список.

+0

Я действительно думал об этом, но вот улов (или, может быть, его нет). Мне нужен вывод для упорядочения (его упорядоченная карта), поэтому потоки должны быть как-то синхронизированы, и я не могу использовать объединения, так как это не имеет никакого значения. – noMAD

1

Если вы используете эти хэш-коды как валидаторы, вы можете придерживаться MD5 или SHA1. Но если вы используете эти хэш-коды как идентификаторы, для которых коллизии, хотя и не предпочтительны, не являются игровым прерыванием, чем есть много быстрых альтернатив, которые вы можете рассмотреть. Быстрая и очень хорошая хэш-информация Боба Дженкина. Вы можете легко преобразовать этот алгоритм для генерации более значимых хеш-кодов очень быстро.

1

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

Простого алгоритм струна база хеширования я использую года назад, происходит от более старого алгоритма первоначально из Bell Labs, был что-то вроде этого:

int hash1(byte[] key) 
{ 
    int  h = 0; 
    for (int i = 0; i < key.length; i++) 
     h = ((h << 3) | (h >>> 32-3))^key[i]; 
    return h; 
} 

Вы можете приспособить это использовать любую часть объекта, хотите, или даже весь объект.

EDIT

я заменил оператор >> с >>>, согласно предложению @ Holger в поле ниже.

+0

Вы должны использовать '>>>' вместо '>>'; в противном случае вы рискуете, что ваш хэш будет затоплен битом знака «1» после его возникновения. Или просто используйте 'Integer.rotateLeft', так как он будет не только делать это правильно, но, скорее всего, его заменит соответствующая команда CPU, если ее поддерживает собственный процессор. – Holger

0

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

на двухъядерных вы бы достичь максимального ускорения от 2

Смежные вопросы