如何生成绝对独特的GUID?

时间:2011-11-02 13:32:44

标签: c#

有没有办法在每次100%新GUID时生成而没有任何机会在整个应用程序中发生冲突?

由于我无法在八小时内回答我的问题,我想出了解决方案:

internal static class GuidGenerator
{
    private static readonly HashSet<Guid> _guids = new HashSet<Guid>();

    internal static Guid GetOne()
    {
        Guid result;

        lock (_guids)
            while (!_guids.Add(result = Guid.NewGuid())) ;

        return result;
    }
    internal static void Utilize(Guid guid)
    {
        lock (_guids)
            _guids.Remove(guid);
    }
}

此代码是否解决了应用程序中的问题?

编辑:呃,它变得复杂了。线程安全会降低速度。

11 个答案:

答案 0 :(得分:22)

不,没有办法生成绝对唯一的 GUID。只有 3.40282367×10 38 可能的GUID,因此星系会发生碰撞,因此这些标识符也会发生冲突。即使对于单个应用程序,它也取决于应用程序具有多少GUID。除非您的应用程序大于Google的所有索引器,否则您不需要为此而失眠。只需使用Guid.NewGuid()

答案 1 :(得分:16)

不确定。 GUID只是一个128位的值。因此,使用128位整数(例如由两个ulong值表示)并递增它。当您达到128位整数类型的最大值时,您已生成所有可能的GUID。例如:

public IEnumerable<Guid> GetAllGuids()
{
    unchecked
    {
        byte[] buffer = new byte[16];
        ulong x = 0UL;
        do
        {
           byte[] high = BitConverter.GetBytes(x);
           Array.Copy(high, 0, buffer, 0, 8);
           ulong y = 0UL;
           do
           {
               y++;
               byte[] low = BitConverter.GetBytes(y);
               Array.Copy(low, 0, buffer, 8, 8);
               yield return new Guid(buffer);
           } while (y != 0UL);
           x++;
        } while (x != 0UL);
    }
}

注意:

  • 这绝对不是那么有效。
  • 迭代所有可能的ulong值很痛苦 - 我不喜欢 使用do...while ......
  • 如评论中所述,这将产生无效的值UUID s

当然,这绝不是随意的......

在实践中,正如其他人所提到的,Guid.NewGuid发生碰撞的可能性非常小。

答案 2 :(得分:6)

不是100%。但是如果您的GUID生成器运行良好,则碰撞概率非常小。这实际上可以算作0。

随机生成的(第4类)guid有大约120个随机位。从生日问题中你可以看到,一旦你产生大约2 ^ 60或10 ^ 18个GUID,碰撞很可能会发生,这是一个很大的事情。

所以简单地使用Guid.NewGuid()就足够了。


您提出的解决方案不是一个好主意IMO:

  • 如果您有很多GUID
  • ,可能需要大量内存
  • 由于您需要在本地知道所有GUID,因此没有理由首先使用GUID。一个简单的整数计数器也可以完成这项工作。
  • 随机GUID冲突不如故障硬件破坏您的数据结构。

您的代码本身对我来说是正确的。即如果您注册所有GUID并且您的硬件完美运行,并且该软件没有其他错误,则保证不会发生冲突。

当然它也不是线程安全的,这对静态方法来说是意料之外的。

答案 3 :(得分:4)

如果您使用有限数量的字符,那么根据Pigeonhole(也称为Dirichlet)原则,您将有可能收到碰撞。

答案 4 :(得分:3)

var newGuid = Guid.NewGuid();

http://msdn.microsoft.com/en-us/library/system.guid.newguid.aspx

编辑 - 我同意@David Heffernan所说的话。您可以使用适当的机制来生成最佳的唯一标识符,但是这个Universe中很少有东西可以依靠100%。

答案 5 :(得分:3)

如果您的上下文中需要唯一的GUID,请从00000000-0000-0000-0000-000000000000开始并使用增量。除非你达到FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF

,否则所有生成的GUID都是唯一的

答案 6 :(得分:2)

这取决于你想要什么。如果您希望生成的GUID之间具有唯一性,则可以实现。只需维护一个GUID列表,无论何时需要创建一个新的GUID,都要循环,直到找到一个不在列表中的循环。

如果你想要某种全球唯一性,那么全球意味着在整个地球上使用的所有GUID中,那就永远无法实现。

答案 7 :(得分:2)

您可以使用Guid.NewGuid()。它将为您生成GUID,我不相信您会与另一个GUID发生冲突。

答案 8 :(得分:2)

存储当前的GUID对于除了少量GUID之外的任何东西都是不切实际的 - 无论如何都会有极低的碰撞机会。

在现实世界中,您定期生成数百万甚至数十亿的GUID,存储128位值以确保唯一GUID的开销变得不切实际。 (每个GUID 16个字节)

仅需10,000,000,000个GUID,您需要160,000,000,000字节= 156,250,000 Kbytes = 152,588 Mbytes = 149 Gbytes

在大型表中查找时间也会使生成新的唯一GUID的速度变慢到虚拟爬网(在CPU时间范围内),特别是当新GUID与现有值冲突导致生成新GUID时 - 然后需要对其进行检查,等

生成&#39;随机&#39; 128位值,甚至使用像(当前时间*处理器时钟)这样的东西可能会足够接近&#39; - 只有45位足以存储1000年的毫秒数。 128位给你9,671,406,556,917,033,397,649,408倍的许多值。

无论你做什么,即使使用计数器,也会发生128位值的冲突。

答案 9 :(得分:1)

Guid.NewGuid()是生成不会与其他GUID冲突的GUID的最不可能的方式。除非您生成GUID并查看现有GUID以确保它们不存在,否则无法100%确定。

答案 10 :(得分:0)

GUID http://msdn.microsoft.com/en-us/library/system.guid.newguid.aspx

编辑-我同意@David Heffernan的说法。您可以在适当的位置使用该机制来生成最佳的唯一标识符,但是在此Universe中几乎没有什么东西可以指望100%的。