python中快速、大宽度、非加密字符串哈希

python中快速、大宽度、非加密字符串哈希,python,string,hash,high-speed-computing,Python,String,Hash,High Speed Computing,我需要python中的一个高性能字符串哈希函数,该函数生成的整数至少有34位的输出(64位有意义,但32位太少)。还有其他几个问题类似于这个关于堆栈溢出的问题,但在我能找到的所有被接受/投票赞成的答案中,都属于少数几个类别中的一个,它们不适用(出于给定的原因) 使用内置的hash()函数。这个函数,至少在我开发的机器上(使用python 2.7和64位cpu)生成一个32位以内的整数-不够大 使用hashlib。hashlib提供加密哈希例程,其速度远远低于非加密目的所需的速度。我发现这是不言

我需要python中的一个高性能字符串哈希函数,该函数生成的整数至少有34位的输出(64位有意义,但32位太少)。还有其他几个问题类似于这个关于堆栈溢出的问题,但在我能找到的所有被接受/投票赞成的答案中,都属于少数几个类别中的一个,它们不适用(出于给定的原因)

  • 使用内置的
    hash()
    函数。
    这个函数,至少在我开发的机器上(使用python 2.7和64位cpu)生成一个32位以内的整数-不够大
  • 使用hashlib。hashlib提供加密哈希例程,其速度远远低于非加密目的所需的速度。我发现这是不言而喻的,但如果你需要基准和引用来说服你这个事实,那么我可以提供
  • 使用
    字符串。\uuuu hash\uuuu()
    函数作为原型来编写自己的函数。
    我怀疑这将是正确的方法,只是这个特定函数的效率在于它使用了c_mul函数,该函数的长度约为32位—同样,对我来说太小了!非常令人沮丧,它如此接近完美
一个理想的解决方案将具有以下性质,其重要性顺序相对松散

  • 输出范围至少扩展34位,可能是64位,同时在所有位上保持一致的雪崩特性。(连接32位哈希往往会破坏雪崩特性,至少在我的愚蠢示例中是这样。)
  • 便携式。在两台不同的机器上给定相同的输入字符串,两次应该得到相同的结果。这些值将存储在一个文件中,以便以后重新使用
  • 高性能。速度越快越好,因为在我运行的程序执行期间,这个函数将被调用大约200亿次(这是目前性能关键的代码)。它不需要用C编写,实际上只需要性能优于md5(在字符串的内置哈希()领域的某个地方)
  • 接受一个“扰动”(这里最好用什么词?)整数作为输入来修改输出。我在下面举了一个例子(列表格式规则不允许我把它放得更近)。我认为这不是100%必要的,因为它可以通过手动扰动函数的输出来模拟,但将它作为输入给我一种温暖的感觉
  • 完全用Python编写。如果它绝对需要用C语言编写,那么我想这是可以做到的,但是我认为用python编写的函数要比用C语言编写的快20%,这只是因为使用两种不同语言的项目协调问题。是的,这是一个借口,但这是一个愿望清单
  • “扰动”散列示例,其中散列值被一个小整数值n急剧更改

    def perturb_hash(key,n):
        return hash((key,n))
    
    最后,如果你想知道我到底在做什么,我需要这样一个特定的散列函数,我正在对pybloom模块进行完整的重写,以显著提高其性能。我成功地做到了这一点(它现在运行速度快了约4倍,占用了约50%的空间),但我注意到,有时如果过滤器足够大,它的假阳性率会突然飙升。我意识到这是因为哈希函数没有寻址足够的位。32位只能寻址40亿位(请注意,过滤器寻址的是位而不是字节),而我用于基因组数据的一些过滤器是这一数字的两倍或更多(因此最小值为34位)

    谢谢

    看一看。其中包括一些性能数据。应该可以将其移植到Python,纯或作为C扩展。(更新了作者建议使用128位变体,扔掉不需要的位)

    如果64位哈希2适合您,则中有一个Python实现(C扩展),其中包括一些其他非加密哈希变体,尽管其中一些仅提供32位输出

    更新我为Murruld3散列函数做了一个快速的Python包装。你可以在网上找到它;它只需要一个C++编译器来构建;不需要增压

    使用示例和定时比较:

    import murmur3
    import timeit
    
    # without seed
    print murmur3.murmur3_x86_64('samplebias')
    # with seed value
    print murmur3.murmur3_x86_64('samplebias', 123)
    
    # timing comparison with str __hash__
    t = timeit.Timer("murmur3.murmur3_x86_64('hello')", "import murmur3")
    print 'murmur3:', t.timeit()
    
    t = timeit.Timer("str.__hash__('hello')")
    print 'str.__hash__:', t.timeit()
    
    输出:

    15662901497824584782
    7997834649920664675
    murmur3: 0.264422178268
    str.__hash__: 0.219163894653
    
    “字符串”:我假定您希望对Python2.x
    str
    对象和/或Python3.x
    字节和/或
    bytearray
    对象进行散列

    这可能违反了你的第一个约束,但是:考虑使用像

    之类的东西。
    (zlib.adler32(strg, perturber) << N) ^ hash(strg)
    

    (zlib.adler32(strg,扰动器)如果可以使用Python 3.2,那么64位窗口上的哈希结果现在是64位值

    使用内置的hash()函数。至少在我为之开发的机器上(使用 Python2.7和一个64位cpu)生成一个32位以内的整数,这个整数的大小不足以 我的目的

    不是这样。内置的哈希函数将在64位系统上生成64位哈希

    这是来自
    Objects/stringobject.c
    (python版本2.7)的python str哈希函数:

    static long
    字符串\u散列(PyStringObject*a)
    {
    寄存器Py_ssize_t len;
    寄存器无符号字符*p;
    寄存器长x;/*请注意64位哈希,至少在64位系统上是这样*/
    如果(a->ob_shash!=-1)
    返回a->ob_shash;
    len=Py_尺寸(a);
    p=(无符号字符*)a->ob_sval;
    x=*p=0)
    x=(1000003*x)^*p++;
    x^=Py_尺寸(a);
    如果(x==-1)
    x=-2;
    a->ob_shash=x;
    返回x;
    }
    
    小心使用内置的哈希函数

    自从Python3以来,每次解释器启动时都会给它注入不同的种子(我不知道更多的细节),因此每次它都会生成不同的值——但不会使用本机数字类型

    $ python3 -c 'print(hash("Hello!"), hash(3.14))'
    -1756730906053498061 322818021289917443
    $ python3 -c 'print(hash("Hello!"), hash(3.14))'
    -4556027264747844925 322818021289917443
    $ python3 -c 'print(hash("Hello!"), hash(3.14))'
    -4403217265550417031 322818021289917443
    

    我一直在使用Python2.7,但是如果3.x引擎中的散列宽度是
    $ python3 -c 'print(hash("Hello!"), hash(3.14))'
    -1756730906053498061 322818021289917443
    $ python3 -c 'print(hash("Hello!"), hash(3.14))'
    -4556027264747844925 322818021289917443
    $ python3 -c 'print(hash("Hello!"), hash(3.14))'
    -4403217265550417031 322818021289917443