【问题标题】:Why is String.GetHashCode() implemented differently in 32-bit and 64-bit versions of the CLR?为什么 String.GetHashCode() 在 32 位和 64 位版本的 CLR 中实现不同?
【发布时间】:2011-07-25 08:10:48
【问题描述】:

32 位和 64 位版本的 string.GetHashCode() 存在差异背后的技术原因是什么?

更重要的是,为什么 64 位版本在遇到 NUL 字符时似乎会终止其算法?例如,以下表达式在 64 位 CLR 下运行时均返回 true。

"\0123456789".GetHashCode() == "\0987654321".GetHashCode()
"\0AAAAAAAAA".GetHashCode() == "\0BBBBBBBBB".GetHashCode()
"\0The".GetHashCode() == "\0Game".GetHashCode()

当我们在字典中使用此类字符串作为键时,这种行为(错误?)表现为性能问题。

【问题讨论】:

  • 非常有趣的发现。事实上,这很可能是一个错误 - 我无法想象这是预期的行为,除非哈希函数不适用于 .Net 字符串。

标签: c# hash clr


【解决方案1】:

这似乎是微软不会修复的已知问题:

正如您所提到的,这对于某些程序来说将是一个重大更改(即使它们不应该真正依赖此),这种风险被认为太高,无法在当前版本中解决此问题。

我同意这将导致默认 Dictionary 中的冲突率会因此而膨胀。如果这会对您的应用程序性能产生不利影响,我建议您尝试通过使用接受 IEqualityComparer 的 Dictionary 构造函数之一来解决它,以便您可以提供更合适的 GetHashCode 实现。我知道这并不理想,并希望在 .NET Framework 的未来版本中解决此问题。

来源:Microsoft Connect - String.GetHashCode ignores any characters in the string beyond the first null byte in x64 runtime

【讨论】:

  • 太糟糕了。这个问题当然是个谜。我们花了一段时间才弄清楚这一点。好在我们可以选择在将它们设置为键之前清理我们的字符串。
  • 我不理解任何这种“重大变革”的借口。 GetHashCode 源代码中的 cmets 清楚地表明,哈希的计算从未被认为是永久的。即使一些傻瓜已经开始依赖它,他们也已经遇到了问题,因为哈希码是依赖于架构的。这是一个 MS 错误,应该修复。自 2010 年以来,这一直在减慢我的哈希表。是的,我确实需要将有时 -'\0' 字节转换为字符串,因为字符串是 .Net 中最快的可变大小字典键!
【解决方案2】:

Eric lippert 对此有一个精彩的博客 Curious property in String

Curious property Revealed

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    • 2011-10-26
    • 1970-01-01
    • 1970-01-01
    • 2011-04-09
    • 2012-01-10
    • 2021-07-08
    相关资源
    最近更新 更多