看了 Windows 的 GUID 生成算法,惊掉我下巴。

2021-05-14 17:07:23 +08:00
 3dwelcome

原来没看到官方源代码前,我网上先搜了一下,做足了功课。一般都说 CLSID 的结构定义如下:

typedef struct _GUID {
DWORD Data1; // 随机数
WORD Data2; // 和时间相关
WORD Data3; // 和时间相关
BYTE Data4[8]; // 和网卡 MAC 相关
} GUID;

这看起来很合理,里面除了随机数,即有时间戳保证时间不重复,又有网卡保证物理区域不重复。

微软有专门生成 GUID 的 API, 叫 CoCreateGuid 给程序员调用。我看了代码,底层调用了 UuidCreate()。精彩部分的来了,查了 github 上的微软泄漏 UuidCreate()源代码后,发现整个函数核心就一句:

RpcStatus = GenerateRandomNumber((unsigned char *)Uuid, 16);

是的你没看错,就是生成 16 个随机数给用户。什么时间和网卡,全部都不存在!

是否碰撞?那就听天由命吧。只要冲突概率最小,那就可以忽略。(比如 TCP 包校验也有记录冲突,但同样选择忽略,具体可看这个贴: https://www.v2ex.com/t/767293

7803 次点击
所在节点    分享发现
58 条回复
3dwelcome
2021-05-14 19:00:20 +08:00
@kop1989

"GUID 类并没有承诺 GUID 一定是 100%不重复的。"

你去 wiki 查一下 guid, 有不是随机数,基于时间戳的版本(微软内部用的版本,比如早期 Office 的 COM GUID,都是这个生成的)。

原理就是写入 100ns 为间隔的时间戳,只要大于这个时间段生成的 GUID,就可以保证时间上无冲突,另外机器 ID 或者网卡 MAC,能保证空间上无冲突。

只要时空都能保证,那么就是 100%无冲突版本的 GUID 。也就是微软一开始用 GUID 算法的版本。
GuuJiang
2021-05-14 19:04:27 +08:00
@3dwelcome 只要一个东西是固定长度的,就不可能存在 100%不重复,鸽笼原理了解一下?
Mutoo
2021-05-14 19:04:44 +08:00
GUID 在同一个 business domian 里面重复的概率非常低,基本上可以忽略。不过全世界那么多 business domain,纯在相同的 GUID 是必然的。

但是我写的 APP 里面有一个跟你写的 APP 里有一个相同的 GUID 又如何?这是两个风马牛不相及的业务,并不会真正「冲突」。所以你要是担心重复,可以给你的业务逻辑再加细分子域就可以了。
EPr2hh6LADQWqRVH
2021-05-14 19:06:57 +08:00
只能说你对指数没有敬畏,2^128 什么概念缺少感性认识
3dwelcome
2021-05-14 19:09:40 +08:00
@GuuJiang 没说永远不重复,WIKI 上写了,GUID v1/v2 算法,到 3400 年之前,都不会重复。时间是不会倒流的。

@Mutoo 微软这个 GUID 生成的 COM Interface,不同软件安装后,写入的是同一个用户注册表。
也就是全球开发人员用的 domain, 在同一个地方。
3dwelcome
2021-05-14 19:11:46 +08:00
@avastms 你买云服务器,可靠性 100%和可靠性 99.9999%,就是本质上的区别。
数的就是小数点后面,有几个 9 。
Mutoo
2021-05-14 19:11:48 +08:00
@3dwelcome 这个只能算是一个微软操作系统上的一个 business domain 。 全球开发者写再多软件,2^128 也够保证微软在有生之年使用了。而你软件业务上的其它 GUID 并不会跟这个 domain 冲突。
Aoang
2021-05-14 19:18:18 +08:00
用过 UUID 的都知道 v4 冲突的概率比 v1 小的多。

v4 一共有 2^128 个 UUID,而 v1 在同一时间同一机器才留了几位给随机数。

只要时间机器相同,v1 就是渣渣,这也是为什么没人用的原因。同一机器多个进程就傻了。

另,因为要用时间戳,v1 只会越用越少。
EPr2hh6LADQWqRVH
2021-05-14 19:19:04 +08:00
@3dwelcome 就是说 2^1024 也满足不了你呗。。。

那建议你注意心理卫生。。。
hoyixi
2021-05-14 19:22:27 +08:00
代码烂很正常,winxp 之前蓝屏司空见惯,谁的 win 里面还不养几种病毒当宠物
skies457
2021-05-14 19:31:18 +08:00
@3dwelcome "原理就是写入 100ns 为间隔的时间戳,只要大于这个时间段生成的 GUID,就可以保证时间上无冲突" -> 连续生成几个就懵逼了吧
3dwelcome
2021-05-14 19:43:10 +08:00
@skies457 微软没那么傻,我看了代码,针对 100ns 额外处理有很多,也有随机数来保障。
比如预生成很多 guid 后,系统 cache 起来的。你代码获取到的 guid,时间戳有可能是早期的。
NXzCH8fP20468ML5
2021-05-14 19:43:22 +08:00
@3dwelcome 时间确实不会倒流,但不代表你电脑上的时间就正确啊。
3dwelcome
2021-05-14 20:17:37 +08:00
@xxfye “但不代表你电脑上的时间就正确啊。”

不同电脑就代表着空域不同,GUID 最后面 8 个 BYTE,就是用来保证空间不一致的。

有个 SSL 设计我想顺便提一下,人家的 random 就不是单纯的随机数,是包含时间戳的。时间是很重要的变量,在一定程度上,要比随机数可控。

0bit
2021-05-14 20:18:43 +08:00
就是 UUID v1 和 v4 之争 呗,实际使用中一直用 v4,没用过 v1 。
geelaw
2021-05-14 20:56:09 +08:00
谁说时间不会倒流的😅 Windows 有 NTP 时间校准机制,很容易发生时间倒流的情况。当然要确保有生之年生成真·不重复的 GUID 也很容易,人工控制时间戳、使用被毁灭的网卡的 MAC 地址并用 v1 算法即可。

毁灭网卡的例子:
https://devblogs.microsoft.com/oldnewthing/20040211-00/?p=40663
3dwelcome
2021-05-14 21:45:38 +08:00
@geelaw 其实本帖的主旨,就在于一个时间序列人为可控,另一个纯随机数不可控。

微软如果当年在 CoCreateGuid 里多加几个参数,别全部依赖于随机函数,也就没这个帖子了。
billlee
2021-05-14 22:13:16 +08:00
MAC 地址也才 48 bits, 现在虚拟机这么多,MAC 也无法保证唯一。所以还不如整个 128 bits 的随机数让冲突概率小一点
billlee
2021-05-14 22:20:42 +08:00
至于 TCP 那个问题,我觉得应该理解为是当时的历史问题。那个时代 CPU 性能太差,而链路层一般都有强校验,所以 TCP 不太需要强校验了
lance6716
2021-05-15 00:47:19 +08:00
不知道楼主有没有用 git,git 也是会有几率遇到哈希冲突的哦,难不难受

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/776972

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX