一个GUID是否总是唯一的?

668

GUID是否100%独一无二?

在多个线程上,它是否仍然保持独一无二?


331
不,不是100%...只有99.999999999999999999999999999999999999999999999999999999999999999999999999999999%;) - JohannesH
66
首先,GUID并不是无限的,这意味着字面上的“100%时间”的意思是,无论您生成多长时间的GUID,它们总是唯一的。但事实并非如此。由于原始实现中使用网络卡唯一的序列号/ID/MAC来产生密钥的方法已不再使用,因此GUID现在不再全球唯一。但它仍然是本地唯一的。换句话说,如果您在单台机器上不断生成GUID,则不会出现重复。 - Lasse V. Karlsen
37
@ojrac 我只是选择向下取整... :P - JohannesH
531
每次我生成GUID时,都感觉自己从宇宙中窃取了一个。有时我会想到那些生成比他们需要更多GUID的邪恶人,那些被浪费掉的GUID是如此孤独,无法再次被使用或生成...... - asavartsov
63
@asavartsov 我认为你会喜欢这个网站:http://www.wasteaguid.info/ ^_^ - Navin
显示剩余16条评论
25个回答

533
虽然每个生成的GUID并不能保证唯一,但唯一键总数(2128 或 3.4×1038)非常大,因此生成相同数字的概率非常小。例如,考虑到可观测宇宙中包含约5×1022颗恒星;那么每颗恒星都可以拥有6.8×1015个全球唯一的GUID。

资料来源:维基百科


以下是一些关于如何生成GUID(针对.NET)以及在正确情况下如何获得同一个guid的好文章。

https://ericlippert.com/2012/04/24/guid-guide-part-one/

https://ericlippert.com/2012/04/30/guid-guide-part-two/

https://ericlippert.com/2012/05/07/guid-guide-part-three/


139
那他们不就应该被称为UUID了吗? ;) - Arafangion
38
GUID是微软对UUID标准的特定实现,因此它既是全局唯一标识符(GUID),也是通用唯一标识符(UUID)。 - Adam Davis
48
从技术上讲,它不是2^128,因为在v4 GUID中,你有一个十六进制数字将始终为4(有效地删除4位),另外还保留了两个位。然而,2^122个有效的V4 GUID仍然有大约5x10^36个,这对我和你来说都足够了。每颗星将不得不接受大约1.1x10^14个GUID。 - Andrew Shelansky
87
如果您和我一样,那么您可能想知道 2^128 的值是多少,它大约等于:34,028,236,692,093,846,346,337,460,743,177,000,000。统计学上来说,如果每秒计算1000个GUID,要产生重复的概率需要经过数万亿年才可能发生。 - Entity
41
我很开心把它读出来,希望你们也玩得开心 :) 三千四百万万亿万亿亿亿亿亿亿亿亿亿二千八百二十八千万万万万万亿六千九百二十亿九千三百八十四万六千三百四十六兆三千三百三十七亿四千六百亿七千四百三十七万一千七百七十。 - hjavaher
显示剩余19条评论

172

如果您害怕相同的GUID值,那么请将它们放在一起。

Guid.NewGuid().ToString() + Guid.NewGuid().ToString();

如果你过于多疑,那就加三个。


135
你必须非常、非常、非常、非常地多疑才会附加3个GUID。 - harsimranb
61
@harsimranb 不...非常、非常、非常、非常的偏执狂是6个GUID。偏执狂是一个附加的,非常偏执狂是两个附加的,以此类推。 - Suamere
132
@Suamere 我已经创建了一个用于计算你的偏执水平的网站 https://jogge.github.io/HowParanoidAmI/。 - Jogge
14
@Jogge xD 这太棒了,哈哈。在您的表单中输入九个"9"后面跟着一个 "999999999",我认为我的浏览器都快要爆炸了。 - Suamere
7
@Jogge,当我输入我是一个拥有10,000级偏执狂的人后,你的网站崩溃了。现在我变得更加偏执了。 - stingray_
显示剩余3条评论

77
简单的答案是肯定的。
Raymond Chen写了一篇很棒的文章关于GUID和为什么GUID的子字符串不保证唯一。这篇文章深入探讨了GUID的生成方式和它们用来确保唯一性的数据,这应该会解释为什么它们是唯一的 :-)

27
我认为陈的文章提到的是GUID生成算法的V1版本,它使用MAC地址和时间戳--目前的V4版本改用伪随机数:http://en.wikipedia.org/wiki/Globally_Unique_Identifier#Algorithm - Barrett

49
作为一个侧面的注释,我在Windows XP中尝试了一些卷GUID。这是一个非常晦涩的分区布局,有三个磁盘和十四个卷。
\\?\Volume{23005604-eb1b-11de-85ba-806d6172696f}\ (F:)
\\?\Volume{23005605-eb1b-11de-85ba-806d6172696f}\ (G:)
\\?\Volume{23005606-eb1b-11de-85ba-806d6172696f}\ (H:)
\\?\Volume{23005607-eb1b-11de-85ba-806d6172696f}\ (J:)
\\?\Volume{23005608-eb1b-11de-85ba-806d6172696f}\ (D:)
\\?\Volume{23005609-eb1b-11de-85ba-806d6172696f}\ (P:)
\\?\Volume{2300560b-eb1b-11de-85ba-806d6172696f}\ (K:)
\\?\Volume{2300560c-eb1b-11de-85ba-806d6172696f}\ (L:)
\\?\Volume{2300560d-eb1b-11de-85ba-806d6172696f}\ (M:)
\\?\Volume{2300560e-eb1b-11de-85ba-806d6172696f}\ (N:)
\\?\Volume{2300560f-eb1b-11de-85ba-806d6172696f}\ (O:)
\\?\Volume{23005610-eb1b-11de-85ba-806d6172696f}\ (E:)
\\?\Volume{23005611-eb1b-11de-85ba-806d6172696f}\ (R:)
                                     | | | | |
                                     | | | | +-- 6f = o
                                     | | | +---- 69 = i
                                     | | +------ 72 = r
                                     | +-------- 61 = a
                                     +---------- 6d = m

并不是GUID非常相似,而是所有GUID中都有字符串“mario”。这是巧合还是有什么解释呢?

现在,在GUID中搜索第4部分,我发现大约有125,000个与卷GUID相关的搜索结果。

结论:当涉及卷GUID时,它们并不像其他GUID那样独特。


40
还记得80年代的《超级马里奥兄弟3》广告吗?全世界那些人们高喊着“马里奥!马里奥!马里奥!”有点打破了宇宙的随机性。 - MGOwen
29
如果您使用“msiexec”手动卸载Office 2010,它将列出所有办公程序的MSI GUID。它们都拼写为“0FF1CE”。看起来微软对于如何生成GUID有相当宽松的解释方式 ;) - Mark Henderson
3
这些分区GUID都是在2009年12月17日下午2:47:45 UTC一起创建的。它们是您计算机独有的,但使用“mario”作为节点标识符是不正确的 - 这意味着它们不符合RFC-4122标准。同样地,“0FF1CE” GUID属于RFC-4122的“NCS向后兼容性”部分,但微软可能没有遵循这些值的NCS规则。 - Stephen Cleary
24
我知道了,任天堂安全管理部门已经破解了随机数生成器。 - MetaGuru
2
也许这和一家生产矿泉水(听说他们是市场领导者)的公司名字相似,Evian。反过来拼写就是Naive :-) - Mariusz
显示剩余5条评论

39

这不应该发生。然而,当 .NET 承受重负时,可能会出现重复的 GUID。我有两个使用不同 SQL 服务器的网络服务器。我试图合并数据,结果发现 1500 万个 GUID 中居然有 7 个重复。


1
这在两台不同的机器上怎么可能呢?我以为 GUID 的一部分是机器名?(不是在争论...只是在问) - John Cruz
11
这只适用于使用 MAC 地址(而非机器名称)作为 GUID 生成的一部分的 v1 GUID。v4 GUID 是事实上的标准,不再使用 MAC 地址,而是使用伪随机数。 - Xander
19
Guid.NewGuid 始终生成 v4 GUID(一直如此)。Tim 可能使用了非常糟糕的熵源。 - Stephen Cleary
2
这个问题是否曾经被复制过?如果是这样的话,那将是一个巨大的问题。 - Zyo
2
在导入非常大的数据集时,我也遇到了同样的问题。从大约1000万到1亿条数据中,你会从Guid.NewGuid得到重复的结果。 - Stephan Baltzer
3
@StephanBaltzer,不,这是不可能的。如果您确实遇到了这种情况,那么可能是您的代码出现了错误,例如截断了GUID或混淆了数据行。事实上,更有可能存在于NewGuid实现中的bug,而不是在没有bug的情况下观察到此冲突。但是,迄今为止还没有报告过这样的bug,因此我敢打赌你的问题是由于你的代码导致的。 - Konrad Rudolph

31

是的,GUID应该始终保持唯一性。它基于硬件和时间,再加上一些额外的位来确保其唯一性。理论上可能会出现两个相同的情况,但在实际情况下极不可能发生。

这是 Raymond Chen 写的一篇关于 GUID 的好文章:

https://blogs.msdn.com/oldnewthing/archive/2008/06/27/8659071.aspx


6
这篇文章有些过时,提到的是GUIDs的v1版本。而v4版本不再使用硬件/时间,而是采用随机数算法。https://en.wikipedia.org/wiki/Globally_unique_identifier#Algorithm - Mani Gandham
此链接已损坏。 - Marcel
这是链接:https://devblogs.microsoft.com/oldnewthing/20080627-00/?p=21823 - Olanrewaju O. Joseph

29

Guid(全局唯一标识符)是在统计学上唯一的。假设Guid生成代码没有bug,两个不同客户端生成相同的Guid的概率非常小,就像担心你的处理器因宇宙射线而出现故障,今天决定2+2=5一样。

多个线程分配新的Guid将获得唯一值,但您应该确保调用的函数是线程安全的。这是在哪个环境中?


根据规范,根据您使用的GUID版本而定。一些GUID基于时间和MAC地址。这意味着对于V2,GUID必须在同一机器上在同一皮秒内生成。这就像将1000个便士袋扔到空中,它们都朝上落在一堆侧面上。虽然有可能,但不太可能到不值得提及风险的程度,除非涉及生命安全。 - Urasquirrel

27

Eric Lippert写了一系列关于GUID的非常有趣的文章。

世界上大约有230台个人电脑(当然还有很多手持设备或非PC计算设备,具有更多或更少相同的计算能力,但让我们忽略这些)。假设我们将全世界所有的PC用于生成GUID;如果每台PC每秒可以生成220个GUID,则仅需大约272秒(一千五百万亿年)--就会有一个非常高的机会生成与您特定GUID相冲突的GUID。并且在三万亿年后,发生碰撞的概率就相当大了。


37
在下一段中他继续说道:“但这是在寻找与特定GUID的冲突。 [...] 因此,如果我们让这十亿台个人电脑生成122位的随机GUID,那么当大约生成2^61个GUID时,其中两个GUID发生冲突的概率就变得非常高了。由于我们假设大约有2^30台计算机每秒产生2^20个GUID,因此我们预计在大约2^11秒后会出现冲突,这大约是1小时。”(最后他解释说,实际上并没有生成那么多的GUID。) - Arjan

25
理论上讲,GUID并非独一无二的。可以多次生成相同的GUID。但是,这种情况发生的几率如此之低,以至于您可以假设它们是独一无二的。
我之前阅读过这样的文章,内容是GUID重复的几率非常低,所以您确实应该关注其他事情——比如您的服务器突然自燃或代码中的其他错误。也就是说,假定它是唯一的,并不需要编写任何“捕获”重复项的代码——把时间花在更有可能发生的事情上(例如任何其他事情)。
我曾尝试向我的博客观众(非技术性亲属)描述GUID的有用性。通过维基百科显示,生成重复的GUID的概率为:
  • 1/2^128
  • 1/340不可思议(不要担心,"不可思议"不在问题之中)
  • 1/3.4 × 10^38
  • 1/340,000,000,000,000,000,000,000,000,000,000,000,000

5
实际上,我对“不用担心这个”持不同意见,尽管是从不同的角度来看:如果您确实检测到GUID冲突,则表示应用程序出现了问题。例如,我曾经使用GUID来实现幂等性,在发送相同GUID两次的命令时遇到了冲突。 - Kenny Hung

22

似乎没有人提及这种情况发生的实际数学概率。

首先,假设我们可以使用整个128位空间(Guid v4仅使用122位)。

我们知道在选取中未重复的一般概率为:

(1-1/2128)(1-2/2128)...(1-(n-1)/2128)

由于2128远远大于n,因此我们可以将其近似为:

(1-1/2128)n(n-1)/2

因为我们可以假设n远远大于0,所以我们可以将其近似为:

(1-1/2128)n^2/2

现在我们可以将其等同于“可接受”的概率,假设为1%:

(1-1/2128)n^2/2 = 0.01

我们解出n并得到:

n = sqrt(2* log 0.01 / log (1-1/2128))

Wolfram Alpha计算得到的结果是 5.598318 × 10 19

为了说明这个数字,假设有10000台机器,每台机器都有一个4核CPU,时钟频率为4Ghz,并花费10000个周期来生成Guid并什么也不做。那么它们需要大约111年才能生成重复的Guid。


我已经根据这篇帖子编辑了你的帖子 - 如果我犯了错误,请进行编辑。 - shA.t
嗨@Cine,我有编辑你的回复的权力,但选择不这样做,因为我想给你反驳的机会,如果一个月内没有收到你的回信,我可能会来正式更改它。我几乎确定你的数学是错的。确定1%概率的真实方程式是:((2 ^ 128-1) / 2 ^ 128) ^ ((n(n-1)) / 2) = .01。你的指数是错误的。它不仅仅是“n”。当您生成“n”个GUID时,需要C(n,2)(又名(n *(n-1))/ 2)来计算所有组合。在此处查看更多信息。 - viggity
谢谢Cine,我也最终近似计算了n^2/2,因为它太大了 :) - viggity
需要10000台机器111年才能生成每一个可能的GUID,然后才会生成一个完全相同的。然而,在生成所有可能的GUID之前,会很早就发生重复。我认为大约需要的时间取决于GUID生成过程有多“随机”。 - George K
3
@GeorgeK 我觉得你误解了... 需要10000台机器111年的时间才有1%的概率遇到重复。但是,这个数学公式当然假设随机生成器是完全随机的。 - Cine
突然间,它似乎并不那么“普遍”独特了。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接