【发布时间】:2011-01-07 04:26:38
【问题描述】:
我想知道 .NET 中 String.GetHashCode() 实现产生的哈希质量和哈希稳定性?
关于质量,我专注于算法方面(因此,哈希的质量会影响大型哈希表,而不是出于安全考虑)。
然后,关于稳定性,我想知道从一个 .NET 版本到下一个版本可能出现的潜在版本控制问题。
非常感谢这两个方面的一些说明。
【问题讨论】:
我想知道 .NET 中 String.GetHashCode() 实现产生的哈希质量和哈希稳定性?
关于质量,我专注于算法方面(因此,哈希的质量会影响大型哈希表,而不是出于安全考虑)。
然后,关于稳定性,我想知道从一个 .NET 版本到下一个版本可能出现的潜在版本控制问题。
非常感谢这两个方面的一些说明。
【问题讨论】:
我无法向您提供有关质量的任何细节(尽管我认为它非常好,因为 string 是框架的核心类之一,很可能用作哈希键)。
但是,关于稳定性,不同版本的框架产生的hash码不保证是一样的,而且过去已经发生了变化,所以绝对不能依赖版本之间hash码的稳定( see here for a reference that it changed between 1.1 and 2.0)。事实上,它甚至在相同框架版本的32位和64位版本之间存在差异; from the docs:
GetHashCode 返回的值是平台相关的。对于特定的字符串值,它在 .NET Framework 的 32 位和 64 位版本上有所不同。
【讨论】:
这是一个老问题,但我想通过提及 this microsoft bug about hash quality 来做出贡献。
总结:在 64b 上,当您的字符串包含 '\0' 字节时,哈希质量非常低。基本上,只有字符串的开头会被散列。
如果像我一样,你必须使用 .Net 字符串来表示二进制数据作为高性能字典的键,你需要注意这个错误。
太糟糕了,这是一个 WONTFIX... 作为旁注,我不明白他们怎么能说修改哈希码是一项重大更改,当代码包含时
// We want to ensure we can change our hash function daily.
// This is perfectly fine as long as you don't persist the
// value from GetHashCode to disk or count on String A
// hashing before string B. Those are bugs in your code.
hash1 ^= ThisAssembly.DailyBuildNumber;
无论如何,哈希码在 x86/64b 中已经不同了。
【讨论】:
我刚刚遇到了一个与此相关的问题。在我的一台计算机(64 位计算机)上,我遇到了一个问题,我追踪到 2 个不同的对象除了(存储的)哈希码之外是相同的。该哈希码是从一个字符串创建的......相同的字符串!
m_storedhash = astring.GetHashCode();
我不知道这两个对象是如何以不同的哈希码结束的,因为它们来自同一个字符串,但是我怀疑发生的事情是在同一个 .NET exe 中,我依赖的类库项目之一已设置为x86 和 ANYCPU 的另一个对象,其中一个对象是在 x86 类库中的方法中创建的,另一个对象(相同的输入数据,相同的所有内容)是在 ANYCPU 类库中的方法中创建的。
那么,这听起来是否合理:在内存中的同一可执行文件中(而不是在进程之间),一些代码可以使用 x86 框架的 string.GetHashCode() 和其他代码 x64 框架的 string.GetHashCode() 运行?
【讨论】:
我知道这并没有真正包含您指定的质量和稳定性的含义,但值得注意的是,散列非常大的字符串会产生 OutOfMemoryException。
【讨论】:
哈希码的质量足以满足其预期目的,即当您将字符串用作字典中的键时,它们不会导致太多冲突。我怀疑如果字符串长度相当短,它只会使用整个字符串来计算哈希码,对于大字符串,它可能只使用第一部分。
不保证跨版本的稳定性。文档清楚地表明哈希算法可能会从一个版本更改为下一个版本,因此哈希码是短期使用的。
【讨论】: