我想证明一个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的代码中出现错误的可能性更大。放弃。

其他回答

这里也有一个解决方案:

int main()
{
  QUuid uuid;
  while ( (uuid = QUuid::createUuid()) != QUuid::createUuid() ) { }
  std::cout << "Aha! I've found one! " << qPrintable( uuid.toString() ) << std::endl;
}

注意:需要Qt,但我保证如果你让它运行足够长的时间,它可能会找到一个。

(注:实际上,现在我正在看它,可能有一些关于生成算法的东西可以防止两个随后生成的uuid发生碰撞——但我有点怀疑)。

for(begin; begin<end; begin)
    Console.WriteLine(System.Guid.NewGuid().ToString());

你不增加begin,所以条件begin < end总是为真。

但你必须确保你有一个副本,还是你只关心是否有一个副本。为了确保有两个人生日相同,你需要366个人(不包括闰年)。如果有超过50%的概率有两个人同一天生日,你只需要23个人。这就是生日问题。

如果你有32位,你只需要77163个值就有超过50%的重复几率。试试吧:

Random baseRandom = new Random(0);

int DuplicateIntegerTest(int interations)
{
    Random r = new Random(baseRandom.Next());
    int[] ints = new int[interations];
    for (int i = 0; i < ints.Length; i++)
    {
        ints[i] = r.Next();
    }
    Array.Sort(ints);
    for (int i = 1; i < ints.Length; i++)
    {
        if (ints[i] == ints[i - 1])
            return 1;
    }
    return 0;
}

void DoTest()
{
    baseRandom = new Random(0);
    int count = 0;
    int duplicates = 0;
    for (int i = 0; i < 1000; i++)
    {
        count++;
        duplicates += DuplicateIntegerTest(77163);
    }
    Console.WriteLine("{0} iterations had {1} with duplicates", count, duplicates);
}

1000 iterations had 737 with duplicates

现在128位已经很多了,所以你仍然在谈论大量的物品,但碰撞的几率很低。对于给定的概率,您需要使用近似值获得以下记录数:

碰撞发生的概率是1/1000 217亿亿亿,50%的几率发生碰撞 396亿亿,90%的碰撞概率

每年大约发送1E14封电子邮件,所以在这个水平上大约需要40万年,你才能有90%的机会拥有两个具有相同GUID的电子邮件,但这与说你需要运行宇宙年龄830亿倍的计算机或太阳变冷才能找到副本有很大不同。

这个程序虽然有错误,但证明了GUID不是唯一的。那些试图证明相反情况的人没有抓住重点。这句话只是证明了一些GUID变体的弱实现。

GUID在定义上不一定是唯一的,它在定义上是高度唯一的。你刚才精炼了高度的意思。根据版本、实现者(MS或其他)、虚拟机的使用等不同,您的定义会发生很大变化。(见前文链接)

你可以缩短你的128位表来证明你的观点。最好的解决方案是使用哈希公式来缩短重复的表,然后在哈希发生冲突时使用完整的值,并基于此重新生成一个GUID。如果从不同的位置运行,则将哈希/完整密钥对存储在一个中心位置。

Ps:如果目标只是生成x个不同的值,那么创建一个这个宽度的哈希表,并检查哈希值。

你可以散列guid。这样,你就能更快地得到结果。

哦,当然,同时运行多个线程也是一个好主意,这样可以增加竞态条件在不同线程上两次生成相同GUID的机会。