2013-09-26 34 views
1

目前,我實現哈希生成的方式不可擴展。我監視了visualVM中的運行,並看到在MessageDigest中花費了太多的CPU時間。下面是代碼:生成大量哈希的優化方式

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[]>。我使用番石榴的哈希和輸入地圖將是巨大的。有什麼我可以在這裏做得更好嗎? 我需要散列所有這些值的原因是因爲我需要將它們存儲在HBase中。

編輯我在這裏使用的哈希算法是MD5

+0

我會尋找一個更簡單的散列,一個直接操作字節數組。在String中使用的散列算法可能相當不錯:'s [0] * 31 ^(n-1)+ s [1] * 31 ^(n-2)+ ... + s [n-1]'。如果你看看源代碼,算法是一個簡單的for循環,其中h = 31 * h + val [off ++];'inside ,. –

+1

如果你使用'hashFunction.hashBytes(value)'而不是'hashFunction.newHasher()。putBytes(value).hash()',一些散列函數的運行速度會更快 - 而且沒有一個會運行得更慢。 –

回答

1

加密安全散列過程是非常CPU密集型的,所以有非常小的,你可以做進一步的優化代碼。我認爲這是不可能讓你的value陣列大大縮短。

你可以做的一件事就是讓你的循環更快地完成:如果你的處理器有多個內核,你可以通過將數據提供給幾個工作線程計算MD5散列並給出你支持結果。

我需要的輸出責令實現,這將使得對{Integer, byte[]}是配對與在輸出列表中各自的指數被散列字節的隊列

的一種方式。預先調整列表someList應該讓您避免必須同步將結果寫回列表中。

+0

我的確想到了這一點,但這裏是捕捉(或者不是)。我需要對輸出進行排序(它是一個有序映射),所以線程需要以某種方式同步,並且我不能使用連接,因爲它們沒有區別。 – noMAD

1

如果您使用這些哈希碼作爲驗證器,您可能想要堅持使用MD5或SHA1。但是,如果你使用這些散列代碼作爲標識符,雖然不是首選,但它們並不是遊戲破解者,而是有許多快速替代品可以考慮。鮑勃詹金的一次一個的散列速度非常快,非常好。您可以輕鬆地將該算法轉換爲非常快速地生成更大規模的哈希碼。

1

如果我瞭解您的應用程序,看起來您不需要密碼安全的單向散列,因爲您僅將散列值用作唯一數據庫索引,而不是用於篡改檢測。所以使用這麼多的CPU爲對象派生一個僞唯一值沒有意義,因爲可以使用簡單但更快的算術聚合算法來代替對象,該算法通過組合一些哈希對象的字節來計算值。

一個簡單的字符串基散列算法我採用年前,從舊的算法得出最初是從貝爾實驗室,是這樣的:

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

你能適應這種使用對象的任何部分,你想要,甚至整個對象。

編輯

我更換了>>運營商>>>,按以下@霍爾格的建議。

+0

你應該用'>>>'代替'>>';否則一旦發生散列,就會冒着散列的'1'符號冒險。或者只是使用'Integer.rotateLeft',因爲它不僅可以正確執行,而且如果本地CPU支持,它可能會被相應的CPU指令替代。 – Holger

0

在多核機器上,您可以運行多個線程來並行計算這些散列,因爲兩個輸入值之間不存在依賴關係。

在一個雙核心,你會實現最大加速2