hash - Bob Jenkins 的 Hash 性能不佳

标签 hash go benchmarking bloom-filter

我正在构建一个 Bloom 过滤器并查看要使用的哈希值和 Bob Jenkins' hash由于分布均匀,这似乎是一个不错的选择。 我将给定的 C++ 代码改编为 Go(可能犯了一个错误,但它似乎有效)。

我着手对哈希的成本进行基准测试,发现 Go std 库中的 SHA1 哈希要快得多。

PASS
BenchmarkJenkins     1000000          2649 ns/op
BenchmarkSHA256  1000000          1218 ns/op
BenchmarkSHA1    5000000           462 ns/op

当我读到您不应在此用例中使用加密哈希时,我是否被误导了? 还是标准库代码比我的优化得多?

package jenkins

import (
    "bytes"
    "encoding/gob"
)

// adapted from http://bretmulvey.com/hash/7.html
func ComputeHash(key interface{}) (uint64, error) {
    var buf bytes.Buffer
    enc := gob.NewEncoder(&buf)
    err := enc.Encode(key)
    if err != nil {
        return 0, err
    }
    data := buf.Bytes()

    var a, b, c uint64
    a, b = 0x9e3779b9, 0x9e3779b9
    c = 0
    i := 0

    for i = 0; i < len(data)-12; {
        a += uint64(data[i]) | uint64(data[i+1]<<8) | uint64(data[i+2]<<16) | uint64(data[i+3]<<24)
        i += 4
        b += uint64(data[i]) | uint64(data[i+1]<<8) | uint64(data[i+2]<<16) | uint64(data[i+3]<<24)
        i += 4
        c += uint64(data[i]) | uint64(data[i+1]<<8) | uint64(data[i+2]<<16) | uint64(data[i+3]<<24)

        a, b, c = mix(a, b, c)
    }

    c += uint64(len(data))

    if i < len(data) {
        a += uint64(data[i])
        i++
    }
    if i < len(data) {
        a += uint64(data[i]) << 8
        i++
    }
    if i < len(data) {
        a += uint64(data[i]) << 16
        i++
    }
    if i < len(data) {
        a += uint64(data[i]) << 24
        i++
    }

    if i < len(data) {
        b += uint64(data[i])
        i++
    }
    if i < len(data) {
        b += uint64(data[i]) << 8
        i++
    }
    if i < len(data) {
        b += uint64(data[i]) << 16
        i++
    }
    if i < len(data) {
        b += uint64(data[i]) << 24
        i++
    }

    if i < len(data) {
        c += uint64(data[i]) << 8
        i++
    }
    if i < len(data) {
        c += uint64(data[i]) << 16
        i++
    }
    if i < len(data) {
        c += uint64(data[i]) << 24
        i++
    }

    a, b, c = mix(a, b, c)
    return c, nil
}

func mix(a, b, c uint64) (uint64, uint64, uint64) {
    a -= b
    a -= c
    a ^= (c >> 13)
    b -= c
    b -= a
    b ^= (a << 8)
    c -= a
    c -= b
    c ^= (b >> 13)
    a -= b
    a -= c
    a ^= (c >> 12)
    b -= c
    b -= a
    b ^= (a << 16)
    c -= a
    c -= b
    c ^= (b >> 5)
    a -= b
    a -= c
    a ^= (c >> 3)
    b -= c
    b -= a
    b ^= (a << 10)
    c -= a
    c -= b
    c ^= (b >> 15)
    return a, b, c
}

编辑:

基准代码:

package bloom

import (
    "testing"

    "crypto/sha1"
    "crypto/sha256"
)

func BenchmarkJenkins(b *testing.B) {
    j := jenkinsHash{}

    for i := 0; i < b.N; i++ {
        j.ComputeHash(i)
    }
}

func BenchmarkSHA1(b *testing.B) {
    for i := 0; i < b.N; i++ {
        sha1.Sum([]byte{byte(i)})
    }
}


func BenchmarkSHA256(b *testing.B) {
    for i := 0; i < b.N; i++ {
        sha256.Sum256([]byte{byte(i)})
    }
}

最佳答案

我将赌注放在优化上; Bob Jenkin 的散列应该比任何加密风格的散列(如 SHA)快得多。我敢打赌,标准库为此调用了高度优化的 C(甚至汇编),这就是为什么它能击败未优化的 Go。

https://github.com/reusee/mmh3 似乎有一个有效的 Murmur3 可用于 Go (我没试过)。你可能会更幸运,或者通过调用 C/C++ 来实现你的 Bob Jenkins。

关于hash - Bob Jenkins 的 Hash 性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23436358/

相关文章:

php - 具有长输出长度的 PHP 哈希函数?

go - 在 Go 中使用没有文件的 io.WriteSeeker

algorithm - 在填充stdin的go slice中找到唯一元素

php - 如何确定 CodeIgniter 的速度?

java - 为什么 HashMaps 10 get() 调用性能注释比单个 get() 性能差 10 倍

hash - 我可以在摘要式身份验证中使用已 MD5 编码的密码吗

PHP set Hash 与 Swift 应用程序的 Checked hash 不同

.net - String.GetHashCode() 的复杂性

html - 在 golang html 模板中访问 {{range .}} 范围之外的结构变量

performance - 全局/本地环境影响 Haskell 的 Criterion 基准测试结果