【问题标题】:Comparing string hashes on different machines比较不同机器上的字符串哈希
【发布时间】:2019-06-15 16:24:08
【问题描述】:
  • 我有一堆 ID,它们是字符串形式的,例如 "enemy1", "enemy2"。
  • 我想保存一个进度,取决于我杀死的每个敌人的数量。为此,我使用了像 { { "enemy1", 0 }, { "enemy2", 1 } } 这样的字典。
  • 然后我想通过网络在他可以玩的几台机器(如 PC 和笔记本电脑)之间共享玩家的存档(首先将其序列化为 JSON 文件)。为了减小尺寸和提高性能,我使用哈希而不是完整字符串,使用该算法(因为 MDSN 说,默认哈希算法在不同的机器上可能不同):
int hash_ = 0;
public override int GetHashCode()
    {
        if(hash_ == 0)
        { 
          hash_ = 5381;
          foreach(var ch in id_)
            hash_ = ((hash_ << 5) + hash_) ^ ch;
        }
        return hash_;
    }

所以,问题是:C# 中的 alg 是否会在任何机器玩家使用的机器中返回相同的结果。


UPD:在 cmets 中,我注意到问题的主要部分不清楚。 所以。如果我可以保证反序列化之前的所有文件都将采用相同的编码,那么播放器可以使用的每台机器上的字符表示形式是否相同并且操作^ ch 会给出相同的结果?我的意思是 WinX64/WinX32/Mac/Linux/... 机器

【问题讨论】:

  • 是的,该算法将在每台机器上给出相同的结果。但是,您不应该假设具有相同哈希值的两个字符串必然相等。但我不清楚这与问题的其余部分有什么关系。之后你将如何使用哈希? (如果您想要 close 来保证唯一性,我会在文件上使用加密哈希,例如使用 SHA-256 或 SHA-512。假设具有相同 SHA 哈希的两个文件是相同的。)
  • 如果您正在创建自己的哈希码,那么它在每台机器上都是相同的。但是,如果您依赖 GetHashCode() 的任何默认实现,则无法保证。
  • @JonSkeet,谢谢。我认为不清楚,但主要部分是关于 C# 中的字符表示。如果我可以保证反序列化之前的所有 JSON 将采用相同的编码,那么 Winx86/Winx64/Unix/MAC... 机器上的字符表示形式是否相同?
  • 是的,char 始终是 UTF-16 代码单元。但我仍然不清楚为什么你会使用这种方法而不是获取文件的加密哈希。
  • @JonSkeet 这真的没有意义,因为我没有大量的字符串条目,而且 6% 的交叉点对我来说是可以的。但这完全有道理,而且很重要,谢谢。

标签: c# hash char compare


【解决方案1】:

是的,对于相同的输入,该代码将在每个平台上给出相同的结果。 char 是一个 UTF-16 代码单元,与平台无关,任何给定的 char 都将在每个平台上转换为相同的 int 值。与像这样计算的哈希码一样,您不应该假设相等的哈希码意味着相等的原始值。 (说实话,还不清楚你打算如何使用哈希。)

我要指出的是,您的代码不是线程安全的 - 如果两个线程基本上同时调用 GetHashCode,一个线程可能会看到值 0(因此开始散列),而第二个线程可能会看到interim 结果(由第一个线程计算)并假设这是最终哈希。如果你真的认为缓存在这里很重要(我会先测试一下),你应该使用局部变量计算完整的哈希值,然后仅在完成后将其复制到字段中。

【讨论】:

  • 它将类似于“使用该哈希码查找条目并将其统计信息增加 1”。或“使用该哈希码获取条目并在屏幕上显示其统计信息”。预期的条目数大约会少于 1000 个。
  • @DenisIlyutin:听起来您当时正在使用哈希作为 ID - 这意味着存在冲突问题,除非您还存在原始数据 - 在这种情况下,哈希无济于事反正你的尺寸。为什么不直接创建一个实际 ID?
  • 因为我想隐藏实际 ID,而且它不会影响运行时的大小(仅在消极方面),但会影响我认为 JSON 序列化后的大小(我知道在我的情况下这是不必要的优化,但它仍在研究)。而且,据我所知,int 操作在运行时比string 操作便宜,因此它是缓存哈希值的优化。
  • 那么碰撞呢 - 在我的情况下这种情况不太可能发生,我想我可以忽略它
  • @DenisIlyutin:我会强烈建议不要仅仅忽略哈希冲突,尤其是如果您没有使用旨在使其真正实现的哈希,你真的不太可能看到重复的值。如果您不想公开某些内部 ID,只需生成一个新 ID(例如使用 Guid.NewGuid)。目前您正在使用哈希,就好像它是一个 ID 一样,当像这样的哈希代码 专门 不是为该用例设计的。 (另外,我知道缓存是一种优化 - 但您当前的缓存方法不是线程安全的。)
猜你喜欢
  • 2011-03-27
  • 2015-03-07
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多