优化生成大量哈希的方法

时间:2013-09-26 16:32:42

标签: java

目前,我实现哈希生成的方式不具备可扩展性。我监视了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

4 个答案:

答案 0 :(得分:1)

密码安全散列过程非常耗费CPU,因此您无法进一步优化代码。我认为不可能使value阵列显着缩短。

要使循环更快完成,可以做的一件事就是并行处理流程:如果您的处理器有多个核心,您可以通过将数据提供给计算MD5哈希值的几个工作线程来分配这些核心之间的计算并给您支持结果。

  

我需要订购输出

实现此目的的一种方法是创建一对{Integer, byte[]}的队列,这些对将要对其进行散列的字节与输出列表中的各自索引进行对等。预先调整列表someList的大小应该可以避免同步将结果写回列表。

答案 1 :(得分:1)

如果您使用这些哈希码作为验证器,您可能希望坚持使用MD5或SHA1。但是,如果你使用这些哈希码作为标识符,虽然不是首选,但它们不是游戏破坏者,而是你可以考虑的许多快速替代品。 Bob Jenkin的One-at-a-time哈希非常快且非常好。您可以非常快速地转换该算法以生成更大的哈希码。

答案 2 :(得分: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;
}

您可以对此进行调整,以使用所需对象的任何部分,甚至是整个对象。

修改

根据@ Holger的建议,我将>>运算符替换为>>>

答案 3 :(得分:0)

在多核计算机上,您可以运行多个线程来并行计算这些哈希值,因为两个输入值之间没有依赖关系。

在双核上,你可以达到最大加速2