1

目前,我实现哈希生成的方式是不可扩展的。我监控了 VisualVM 中的运行情况,发现有太多的 CPU 时间花在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[]>. 我正在使用番石榴的哈希器,输入地图会很大。有什么我可以在这里做得更好的吗?我需要散列所有这些值的原因是因为我需要将它们存储在 HBase 中。

编辑我在这里使用的散列算法是MD5

4

4 回答 4

1

加密安全散列过程占用大量 CPU 资源,因此您几乎无法进一步优化代码。我认为不可能使您的value数组显着缩短。

为了更快地完成循环,您可以做的一件事是并行化该过程:如果您的处理器有多个内核,您可以通过将数据提供给计算 MD5 哈希并返回结果的多个工作线程来在这些内核之间分配计算.

我需要订购输出

实现这一点的一种方法是制作一个成对的队列,{Integer, byte[]}将要散列的字节与它们在输出列表中的相应索引进行散列。预先调整列表大小someList应该可以让您避免将结果同步写入列表。

于 2013-09-26T16:41:02.563 回答
1

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

于 2013-09-26T16:52:47.857 回答
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 下面的建议,我用 替换了>>运算符。>>>

于 2013-09-26T16:53:41.787 回答
0

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

在双核上,您将实现 2 的最大加速

于 2013-09-26T16:59:31.467 回答