这是否是使用Python内置哈希函数的适当方式?

26

我需要比较大块的数据以确定它们是否相等,而且我需要每秒比较许多对数据,速度要。每个对象具有相同的长度,但可能会有一些未知位置的轻微差异。

下面的时间表明,如果数据开始处有差异,则使用 == 运算符非常快,而如果差异位于数据末尾,则速度明显较慢。

>>> import os
>>> s = os.urandom(1600*1200 - 1)
>>> Aimg = b"A" + s
>>> Bimg = b"B" + s
>>> img1 = s + b"1"
>>> img2 = s + b"2"
>>> %timeit Aimg == Bimg
61.8 ns ± 0.484 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit img1 == img2
159 µs ± 2.83 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

在我的使用场景中,差异可能位于字节的中间或末尾(背景:这是未压缩的图像数据)。我想寻找一种使用哈希或校验和来加速处理的方法。使用md5会更慢,但Python内置的hash实际上确实提高了速度。

>>> %timeit img1 == img2
160 µs ± 5.96 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
>>> %timeit hash(img1) == hash(img2) and img1 == img2
236 ns ± 5.91 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

我对该哈希的技术细节感兴趣,如果hash(a) == hash(b),那么a == b是非常可能的吗?如果哈希冲突相对较少,则可以接受误报,意图是在平均情况下加速比较。


3
hash 函数是与架构相关的。 - JBernardo
1个回答

41

Python的哈希函数是为了速度而设计的,映射到64位空间。由于生日悖论,这意味着在大约50亿条目(可能更早,因为哈希函数不是密码学的)时,您很可能会遇到碰撞。此外,hash的精确定义取决于Python实现,可能是特定于架构甚至机器的。如果您想在多台机器上获得相同的结果,请不要使用它。

md5被设计为密码学哈希函数;即使是输入的轻微扰动也会完全改变输出。它还映射到128位空间,这使得除非您专门寻找碰撞,否则您几乎不可能遇到任何碰撞。

如果您可以处理碰撞(即通过使用MD5或SHA2等密码算法测试所有成员之间的相等性),Python的哈希函数就完全可以。

还有一件事:如果将数据写入磁盘,为节省空间,应以二进制形式存储数据。(即struct.pack('!q', hash('abc')) / hashlib.md5('abc').digest())。

顺便说一下:在Python中,is==不等价。您应该使用==


这个应该是 !q 而不是 !I 吗?例如 struct.pack('!I', hash('abc')) 给我返回了 struct.error: 'I' format requires 0 <= number <= 4294967295 - Andy Hayden
@AndyHayden 确实。已修复。 - phihag

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接