【问题标题】:How generate unique Integers based on GUIDs如何根据 GUID 生成唯一整数
【发布时间】:2010-05-27 11:37:36
【问题描述】:

是否可以从 GUID 生成(极有可能的)唯一整数?

int i = Guid.NewGuid().GetHashCode();

int j = BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0);

哪个更好?

【问题讨论】:

  • 为什么不将 GUID 用于您使用 32 位整数的任何目的?
  • 在哪个域中唯一?我刚刚编写并执行了一个生成 all 32 位整数的程序,所以你将无法生成我还没有的!
  • 如果你可以忘记Guid,那么获得“唯一”(100%)的最佳方法就是在某处有一个 int 变量并执行 int++。你肯定会得到 2^32 个唯一值,这也是相当大的空间..

标签: c#


【解决方案1】:

Eric Lippert 发表了一篇关于probability of hash collisions 的非常有趣(一如既往)的帖子。

您应该阅读所有内容,但他以这张非常说明性的图表结束:

关于您的具体问题,我也会选择GetHashCode,因为无论哪种方式,冲突都是不可避免的。

【讨论】:

  • 即不要这样做。
【解决方案2】:

GetHashCode 函数专门用于创建具有低冲突概率的分布良好的整数范围,因此对于这个用例可能是您能做的最好的。

但是,我相信您知道,将 128 位信息散列成 32 位信息会丢弃大量数据,因此如果您有足够多的 GUID,几乎肯定会发生冲突。

【讨论】:

  • 如果取“足够大”大于 2^32,可以去掉“差不多”。在这种情况下,碰撞是有保证的。
【解决方案3】:

GUID 是一个 128 位整数(它只是十六进制而不是基数 10)。使用 .NET 4 使用 http://msdn.microsoft.com/en-us/library/dd268285%28v=VS.100%29.aspx,如下所示:

// Turn a GUID into a string and strip out the '-' characters.
BigInteger huge = BigInteger.Parse(modifiedGuidString, NumberStyles.AllowHexSpecifier)

如果您没有 .NET 4,可以查看 IntXSolver Foundation

【讨论】:

  • 这行得通,尽管必须注意产生的数字也是负数,请参阅这个小提琴:dotnetfiddle.net/B97Fhv
  • 使用:Console.WriteLine(huge.ToString().Replace("-","").Remove(30));解决问题@dotnetguy
  • 终于有实际答案了。
【解决方案4】:

这是最简单的方法:

Guid guid = Guid.NewGuid();
Random random = new Random();
int i = random.Next();

您会注意到这里实际上并未使用guid,主要是因为使用它毫无意义。 Microsoft 的 GUID 算法不再使用计算机的 MAC 地址 - GUID 实际上是使用伪随机生成器(基于时间值)生成的,所以如果你想要一个随机整数,使用Random 类更有意义.

更新:实际上,使用 GUID 生成 int 可能比仅使用 Random 更糟糕(“更糟糕”的意思是更有可能 产生碰撞)。这是因为并非 GUID 中的所有 128 位都是随机的。理想情况下,您希望从散列函数中排除不变的位,尽管正如我之前提到的那样,只生成一个随机数会容易得多。 :)

【讨论】:

  • 也许 OP 想要从 GUID 派生整数是有充分理由的。
  • OP 可能认为有充分的理由从 GUID 派生整数(即,为了确保 int 的唯一性),但实际上没有。
  • 如 João Angelo 的答案链接所示,使用 32 位整数发生冲突的可能性很高。 9300 个随机 32 位整数有 1% 的碰撞几率,77000 个有 50% 的碰撞几率。因此,依靠 32 位随机数来实现唯一性是矛盾的。
  • 只是为了可读性:79,228,162,514,264,337,593,543,950,336。
  • 只需加上我的 2 美分......我们所有的密钥都是 GUID,我们调用的网络服务要求密钥是整数。这也是从 GUID 转为整数的原因。
【解决方案5】:

如果您想突破 2^32 的障碍,请尝试以下方法:

/// <summary>
/// Generate a BigInteger given a Guid. Returns a number from 0 to 2^128
/// 0 to 340,282,366,920,938,463,463,374,607,431,768,211,456
/// </summary>
    public BigInteger GuidToBigInteger(Guid guid)
    {
        BigInteger l_retval = 0;
        byte[] ba = guid.ToByteArray();
        int i = ba.Count();
        foreach (byte b in ba)
        {
            l_retval += b * BigInteger.Pow(256, --i);
        }
        return l_retval;
    }

在你经历碰撞之前,宇宙将衰变为冰冷黑暗的广阔空间。

【讨论】:

  • 是的,但有时宇宙崩溃的速度比人们预期的要快。例如,当您将 int32 误认为可以放置 int64 的地方时 - 宇宙是无限的(可能) - int32 不是。而且 Guid 中的字节不是按重要性从左到右排序的,这就是为什么即使宇宙没有崩溃,这仍然是错误的。
【解决方案6】:

我有一个要求,即控制台应用程序的多个实例需要获取唯一的整数 ID。它用于标识实例并在启动时分配。因为 .exe 是手动启动的,所以我选择了使用开始时间刻度的解决方案。

我的理由是用户几乎不可能在同一毫秒内启动两个 .exe。这种行为是确定性的:如果发生冲突,您就知道问题在于同时启动了两个实例。依赖于哈希码、GUID 或随机数的方法可能会以不可预知的方式失败。

我将日期设置为 0001-01-01,加上当前时间并将刻度除以 10000(因为我没有设置微秒),得到一个小到可以放入整数的数字。

 var now = DateTime.Now;
 var zeroDate = DateTime.MinValue.AddHours(now.Hour).AddMinutes(now.Minute).AddSeconds(now.Second).AddMilliseconds(now.Millisecond);
 int uniqueId = (int)(zeroDate.Ticks / 10000);

编辑:有一些警告。为避免发生冲突,请确保:

  • 手动启动实例(间隔超过一毫秒)
  • ID 在每个实例启动时生成一次
  • ID 必须仅对于当前正在运行的其他实例是唯一的
  • 只需要少量的 ID

【讨论】:

  • 这对 Int 值 ID 非常有效 - 我所做的一项更改是使用 DateTime.UtcNow 而不是 DateTime.Now,后者使用机器本地时间。
【解决方案7】:

因为 GUID 空间大于 32 位整数的数量,所以如果您有足够的 GUID,您肯定会发生冲突。鉴于您了解这一点并准备好处理冲突,无论多么罕见,GetHashCode() 正是为此目的而设计的,应该是首选。

【讨论】:

    【解决方案8】:

    也许不是整数,而是小的唯一键,反正比 guid 短:

    http://www.codeproject.com/Articles/14403/Generating-Unique-Keys-in-Net

    【讨论】:

      【解决方案9】:

      在静态类中,保留一个静态常量整数,然后在每次访问之前将其加 1(使用公共 get 属性)。这将确保您在获得非唯一值之前循环整个 int 范围。

          /// <summary>
          /// The command id to use. This is a thread-safe id, that is unique over the lifetime of the process. It changes
          /// at each access.
          /// </summary>
          internal static int NextCommandId
          {
              get
              {
                  return _nextCommandId++;
              }
          }       
          private static int _nextCommandId = 0;
      

      这将在正在运行的进程中产生一个唯一的整数值。由于您没有明确定义整数的唯一性,因此这可能适合。

      【讨论】:

      • ...直到您下次打开应用程序。或者您的网络服务器重新启动。或者您正在运行一个分布式应用程序(多个服务器)。 /显然(我相信你知道)
      • @drzaus 是的,如前所述,它仅在正在运行的进程中是唯一的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-17
      • 2019-03-08
      • 1970-01-01
      • 2011-01-11
      相关资源
      最近更新 更多