我想证明一个GUID在一个简单的测试程序中不是唯一的。
我原以为下面的代码会运行几个小时,但它不起作用。我该怎么做呢?
BigInteger begin = new BigInteger((long)0);
BigInteger end = new BigInteger("340282366920938463463374607431768211456",10); //2^128
for(begin; begin<end; begin++)
Console.WriteLine(System.Guid.NewGuid().ToString());
我用的是c#。
当然guid也会发生碰撞。由于guid是128位的,只需生成其中的2^128 + 1个,根据鸽子洞原理,肯定会有碰撞。
但是当我们说一个GUID是唯一的时,我们真正的意思是键空间非常大,实际上不可能意外地生成两次相同的GUID(假设我们是随机生成GUID)。
如果随机生成n个guid序列,那么至少发生一次碰撞的概率大约是p(n) = 1 - exp(-n^2 / 2 * 2^128)(这是一个生日问题,可能的生日数量为2^128)。
n p(n)
2^30 1.69e-21
2^40 1.77e-15
2^50 1.86e-10
2^60 1.95e-03
为了使这些数字具体化,2^60 = 1.15e+18。所以,如果你每秒生成10亿个guid,你将需要36年才能生成2^60个随机guid,即使这样,你发生碰撞的概率仍然是1.95e-03。在接下来的36年里,你更有可能在生命中的某个时刻被谋杀(4.76e-03),而不是发现一次碰撞。祝你好运。
如果你想在代码的许多地方检查guid的唯一性,你可以使用一个漂亮的小扩展方法。
internal static class GuidExt
{
public static bool IsUnique(this Guid guid)
{
while (guid != Guid.NewGuid())
{ }
return false;
}
}
要调用它,只需调用Guid。每当你生成一个新的guid…
Guid g = Guid.NewGuid();
if (!g.IsUnique())
{
throw new GuidIsNotUniqueException();
}
...见鬼,我甚至建议打电话两次,以确保它在第一轮就得到了正确的答案。