如何生成绝对独特的GUID?

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

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

internal static class GuidGenerator { private static readonly HashSet _guids = new HashSet(); 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); } } 

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

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

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

 public IEnumerable 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的值

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

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

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

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

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

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


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

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

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

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

如果你使用有限数量的字符,那么根据鸽笼 (也称为Dirichlet )原则,你总有可能会遇到碰撞。

 var newGuid = Guid.NewGuid(); 

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

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

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

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

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

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

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

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

对于仅10,000,000,000个GUID,您需要160,000,000,000字节= 156,250,000千字节= 152,588 MB = 149 GB

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

生成“随机”128位值,或甚至使用类似(当前时间*处理器时钟)之类的东西可能“足够接近” – 只有45位足以存储1000年的毫秒计数。 128位为您提供了许多值的9,671,406,556,917,033,397,649,408倍。

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

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