我需要生成大约N = 1亿个键的哈希键。从我的研究看来,murmur3(MurmurHash3_x86_32,见murmur3 hash)将是最快的散列函数,具有最佳延迟和足够小的碰撞率。我面临的问题是函数返回键为void *
。更具体地说,模板是:
void MurmurHash3_x86_32 (const void *key, int len, uint32_t seed, void *out);
由于我的哈希表大小会小于它可以生成的最大哈希值,我需要将它放入表范围[0,N-1]。最简单的解决方案似乎是使用%
运算符。但由于众所周知这是一个缓慢的算子,我想知道是否有更快的方法来解决这个问题。
我发现一个有趣的建议是在StackOverflow本身上给出了Is there an alternative to using % (modulus) in C/C++?。它暗示了两个人的力量,以下作品(假设两个补语表示)':
return i & (n-1);
我的问题是,在较新的CPU上,有时(或者大部分时间都是这样?),由于多路缓存线,性能会下降到大约2 ^ n,IIRC。 (此链接提供有关插入Big Memory, Part 3.5: Google sparsehash!)的说明。
目前,murmur3的优势似乎因硬件相关问题和%
运算符的低效率而无效。由于性能是一个约束,我要求低延迟和更快的解决方案,即使它不是MurmurHash3_x86_32。
答案 0 :(得分:4)
我面临的问题是该函数将键返回为
void *
。
没有。它什么都不返回(void
)。哈希结果通过最后一个参数记录在您指定的缓冲区(指向)中。对于MurmurHash3_x86_32()
,最有意义的是指向uint32_t
的指针。
由于我的哈希表大小会小于它可以生成的最大哈希值,我需要将它放入表范围[0,N-1]。最简单的解决方案似乎是使用%运算符。但由于众所周知这是一个缓慢的算子,我想知道是否有更快的方法来解决这个问题。
%
不仅是最简单的解决方案,也是最常见的解决方案。 "慢动作"是相对的 - %
比+
慢,但很多,很多比调用MurmurHash3_x86_32()
的速度快。
我发现一个有趣的建议[...]建议[使用两个表格大小,并通过
&
运算符计算模数]
请注意,与SO回答中的断言相反,实际上这对两个人来说完全没有依赖性。补充表示。
我的问题是,在较新的CPU上,有时(或者大部分时间都是这样?),由于多路缓存线,性能会下降到大约2 ^ n,IIRC。 (此链接提供有关插入大内存的说明,第3.5部分:Google sparsehash!)。
您链接的报告中描述的性能降级归因于重新散列,这似乎很合理。这与您提出的操作无关。可以想象,缓存(缺少)关联性可能会影响大型哈希表的性能,但可能不会比通常使用大型哈希表更多。使用哈希表时固有的存储器访问模式自然会产生较差的缓存局部性。这实际上就是点。
目前,murmur3的优势似乎因硬件相关问题和%运算符的低效率而无效。由于性能是一个约束,我要求低延迟和更快的解决方案,即使它不是MurmurHash3_x86_32。
你是在暗示这一点。缺乏有效使用CPU缓存只是您使用大型哈希表所付出的代价。它与散列函数无关(只要散列函数完成其工作)。单个算术运算的成本,无论是%
还是&
,与计算哈希在上运行的成本相比都不会引人注意,因此它几乎不重要你选择哪一个。如果您希望在该操作中获得微小的优势,那么请使用两倍大小的表和&
运算符。另一方面,这会丢掉你去计算的麻烦。考虑选择 prime 哈希表大小和%
运算符 - 然后所有哈希位将有助于桶选择,这可能会改善您的传播。