简单证明GUID不是唯一的

Kai*_*Kai 323 c# guid

我想证明一个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());
Run Code Online (Sandbox Code Playgroud)

我正在使用C#.

lig*_*gos 407

Kai,我已经提供了一个程序,可以使用线程做你想做的事.它根据以下条款获得许可:您必须为每个CPU核心每小时支付0.0001美元.费用在每个日历月结束时支付.请尽快与我联系,以获取我的paypal帐户详细信息.

using System;
using System.Collections.Generic;
using System.Linq;

namespace GuidCollisionDetector
{
    class Program
    {
        static void Main(string[] args)
        {
            //var reserveSomeRam = new byte[1024 * 1024 * 100];     // This indeed has no effect.

            Console.WriteLine("{0:u} - Building a bigHeapOGuids.", DateTime.Now);
            // Fill up memory with guids.
            var bigHeapOGuids = new HashSet<Guid>();
            try
            {
                do
                {
                    bigHeapOGuids.Add(Guid.NewGuid());
                } while (true);
            }
            catch (OutOfMemoryException)
            {
                // Release the ram we allocated up front.
                // Actually, these are pointless too.
                //GC.KeepAlive(reserveSomeRam);
                //GC.Collect();
            }
            Console.WriteLine("{0:u} - Built bigHeapOGuids, contains {1} of them.", DateTime.Now, bigHeapOGuids.LongCount());


            // Spool up some threads to keep checking if there's a match.
            // Keep running until the heat death of the universe.
            for (long k = 0; k < Int64.MaxValue; k++)
            {
                for (long j = 0; j < Int64.MaxValue; j++)
                {
                    Console.WriteLine("{0:u} - Looking for collisions with {1} thread(s)....", DateTime.Now, Environment.ProcessorCount);
                    System.Threading.Tasks.Parallel.For(0, Int32.MaxValue, (i) =>
                    {
                        if (bigHeapOGuids.Contains(Guid.NewGuid()))
                            throw new ApplicationException("Guids collided! Oh my gosh!");
                    }
                    );
                    Console.WriteLine("{0:u} - That was another {1} attempts without a collision.", DateTime.Now, ((long)Int32.MaxValue) * Environment.ProcessorCount);
                }
            }
            Console.WriteLine("Umm... why hasn't the universe ended yet?");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

PS:我想试试Parallel扩展库.那很简单.

并且使用OutOfMemoryException作为控制流只是感觉不对.

编辑

嗯,似乎这仍然吸引了选票.所以我修复了GC.KeepAlive()问题.并将其更改为使用C#4运行.

并澄清我的支持条款:支持仅适用于2010年2月28日.请使用时间机器仅在当天提出支持请求.

编辑2 与往常一样,GC比管理内存做得更好; 以前任何以前做过的尝试都注定要失败.

  • 最后一次Console.WriteLine让我真的很开心.我认为你应该抛出一个`CommonlyAcceptedCosmologicTheoriesWrongException`. (120认同)
  • 将此标记为已接受也意味着@Kai接受@ligos规定的条款? (17认同)
  • @devinb请解释一下?看起来它释放了之前分配的字节,以便GC可以"收集()"它.为什么不做任何事情? (4认同)
  • 设置`reserveSomeRam = null;`实际上并没有完成任何事情. (3认同)
  • GuidCollisionDetector.这个名字有潜力 (3认同)
  • 谢谢你的代码.我把它放在我的GUID生成器代码中,用于生成跨数据库外键,这对于防止我们遇到的所有冲突都有很大的帮助.但是,现在我的应用程序冻结了,我看不出为什么?!必须是.Net框架错误或其他东西. (3认同)
  • @ligos:一些评论:你在SO答案中输入的代码必须是公共领域; 我相信你的意思是"宇宙",而不是"univese"; 我将来会运行你的程序; 我在倒退的时候跑了,所以你得给我钱; 令人惊讶的是,它没有发现碰撞,宇宙没有结束的原因与高度充电的递归damma波动核心有关. (2认同)
  • 7小时制,无碰撞.我放弃! (2认同)
  • 我正在起诉我的钱...我已经运行了这个程序3,654,5334年才意识到许多guid不在原始的hashset中!事实上,每次没有碰撞,未来的碰撞都会丢失!我甚至买了一台64埃的ram机器才意识到.net 4最多只能使用9艾字节!这个程序是假的!所有那些丢失的guids在网络空间漫无目的地游荡......我想要100万亿美元的回报! (2认同)

rjm*_*nro 226

这将运行超过数小时.假设它以1 GHz的频率循环(它不会 - 它将慢很多),它将运行10790283070806014188970年.这比宇宙时代长约830亿倍.

假设摩尔定律成立,那么不运行这个程序,等待几百年并在速度快十亿倍的计算机上运行它会快得多.实际上,如果等到CPU速度增加并且在运行之前购买新的CPU,那么任何需要运行时间超过CPU速度加倍(大约18个月)的程序都会很快完成(除非你写它以便它可以在新硬件上暂停和恢复).

  • 四核处理器上的4个线程将使其运行在宇宙时代的200亿倍 - 所以是的,这将有很大帮助. (107认同)
  • 我怀疑这是一个巨魔,但是有可能它不是:线程不是神奇的.如果你可以在一个线程上每秒执行十亿次操作,那么转到十个线程意味着每个线程经常运行十分之一.每个线程每秒执行100 M次操作; 每秒的操作总数不会增加.每秒增加操作次数的方法是购买更多计算机.假设你买了十亿台电脑.这样可以将问题减少到仅花费10790283070806年,这仍然超过四个小时. (34认同)
  • 该死的 - 所以也许产生guid的几个线程是一个更好的主意? (27认同)
  • 我认为rjmunro假设每个线程都运行在一个单独的核心上; 830亿个宇宙/ 4个核心确实大约相当于200亿个宇宙.是时候买英特尔股票了! (10认同)
  • @Erik 830亿个处理器意味着你可以在大约迄今为止宇宙存在的时间内完成它.所以即使这还不够. (4认同)
  • 按照每秒10亿GUID的速度,只有634年才有50%的碰撞几率. (4认同)
  • 摩尔定律实际上并没有谈论CPU速度.它谈到了每个CPU的晶体管数量.这实际上意味着线程将变得与等待更快硬件的论点非常相关. (2认同)

tyl*_*erl 170

GUID在理论上是非唯一的.这是你的证明:

  • GUID是128位数
  • 如果不重新使用旧的GUID,则无法生成2 ^ 128 + 1个或更多GUID

但是,如果太阳的整个输出功率都是针对执行此任务的,那么它在完成之前很久就会变冷.

可以使用许多不同的策略生成GUID,其中一些策略采取特殊措施来保证给定的机器不会两次生成相同的GUID.在特定算法中查找冲突会显示您生成GUID的特定方法很糟糕,但一般不会证明GUID的任何内容.

  • Pigeonhole原则来救援! (44认同)
  • @Skizz:这只适用于暴力攻击.当加密方案被"破坏"时,意味着它可以在比蛮力更短的时间内解决,但是求解时间仍然与密钥大小成比例. (31认同)
  • +1太阳冷评论.关于加密密钥> 256位的无意义,有一个有趣的评论.迭代所有可能的键值将比整个宇宙拥有更多的能量.在CPU中切换一点需要少量的能量(这是产生热量的能量),当乘以2 ^ 256倍时,是超过宇宙中存储的能量的真正大量数字,使用E = mc2,宇宙将需要质量2 ^ 227kg,我们的太阳是2 ^ 101kg所以那是2 ^ 126太阳! (22认同)

jas*_*son 137

当然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
Run Code Online (Sandbox Code Playgroud)

为了使这些数字具体化,2^60 = 1.15e+18.因此,如果您每秒生成10亿个GUID,则需要36年才能生成2^60随机GUID,即使这样,您发生碰撞的概率仍然存在1.95e-03.你更可能是在你的生活中被杀害(4.76e-03)比你找到在未来36年的冲突.祝好运.

  • 如果你在生命中的某个时刻被谋杀,那么它最终可能会被淘汰. (239认同)
  • @mmyers:非常好.这意味着我现在被谋杀的可能性非常低,因为这不是我生命的终点.等一下... (25认同)
  • 你假设被谋杀的可能性是所有人的常数.但显然,在论坛帖子中撰写讽刺言论的人是那种比普通人更容易被谋杀的人. (17认同)

cta*_*cke 61

如果您担心独特性,您可以随时购买新的GUID,这样您就可以扔掉旧的GUID.如果你愿意,我会在eBay上放一些.

  • 在售,每1k GUID 0.01美元.如果你在接下来的60分钟内订购,我会扔一些竹风铃. (23认同)
  • 酷 - 整套的多少,从0到(2 ^ 128)-1? (13认同)
  • 我的套装更独特,质量更高.它们经过双重检查和验证,使每个GUID的价值为1美元.如果您不想一次性完成全部投资,您甚至可以批量购买.我必须每批额外收取10美元. (7认同)
  • 我会为您制定月度计划,并以合适的价格为您提供无限制的指导.那些家伙正在试图欺骗你并向你出售价格过高的guids.我会卖给你在中国制造的优质guids! (3认同)

AMi*_*ico 47

就个人而言,我认为"大爆炸"是两个GUID相撞时引起的.

  • 记住这需要一个"特殊"的程序员才能做到这一点...... (4认同)
  • 如果Timecop告诉我们任何事情,那么同一事物在任何特定时间都不能占据同一个空间.因此,如果两个GUID在哪里发生碰撞,它们会相互消耗,由此产生的内爆会产生一个黑洞,吞噬整个宇宙.所以实际上,它不会创造一个宇宙,它会破坏它. (2认同)

R. *_*des 42

您可以使用量子bogosort算法的变体在O(1)时间内显示.

Guid g1 = Guid.NewGuid();
Guid g2 = Guid.NewGuid();
if(g1 != g2) Universe.Current.Destroy();
Run Code Online (Sandbox Code Playgroud)

  • 我知道我在Haskell编程的原因.这些副作用变得可怕. (61认同)
  • 我在调用Destroy()时遇到异常.根据文本,我认为我的计算机缺乏必要的硬件来摧毁当前的宇宙.你知道我可以在哪里获得它吗? (21认同)
  • @Steven:不,有些管理人员太担心API对公众有多么糟糕,并且由于"安全原因"而导致它总是失败.如果你看一下方法的来源,那就是一行:`throw new MundaneHardwareException();`.无论如何,我听说欧洲核子研究中心的那些人有某种大强子Thingy可能会做的伎俩...... (11认同)
  • @Martinho:啊,好的.我将研究用`Cern.Lhc.DestroyThisUniverse()`替换`Universe.Current.Destroy()`. (7认同)
  • "有一种理论认为,如果有人曾经发现宇宙究竟是为了什么以及为什么它在这里,它会立即消失并被更奇怪的莫名其妙的东西所取代.还有另一种理论认为这已经发生了". - 道格拉斯·亚当斯,"银河系漫游指南" (6认同)
  • @AMissico:我认为重点是摧毁你找不到匹配的所有可能的宇宙,以便在幸存的宇宙中你有匹配.当然,我想知道这些作业是否需要像Guid g1 = Universe.Quantum.Branch(Guid.NewGuid()); 否则,Guid.NewGuid()的伪随机生成的确定性本质将倾向于在从相同初始执行分支的所有Universe中产生相同的结果. (2认同)

Gra*_*ton 28

任何两个GUID很可能是唯一的(不相等).

请参阅此SO条目,以及Wikipedia

虽然不保证每个生成的GUID都是唯一的,但是唯一密钥的总数(2 ^ 128或3.4×10 ^ 38)是如此之大,以至于两次生成相同数字的概率非常小.例如,考虑可观察的宇宙,其中包含大约5×10 ^ 22个星; 然后每个星星都有6.8×10 ^ 15个通用唯一的GUID.

因此,你可能需要等待数十亿年,并希望你在宇宙之前击中一个,因为我们知道它已经结束了.

  • @Infinity - 连你? (45认同)
  • 它是.为什么你认为2 ^ 128是一个小数字? (21认同)
  • 这是一个数字的地狱.`$ irb >> 2**128 => 340282366920938463463374607431768211456` (3认同)

Ste*_*edd 27

[更新:] 正如下面的评论所指出的,更新的MS GUID是V4,并且不使用MAC地址作为GUID生成的一部分(我没有看到MS的任何V5实现的迹象,所以如果有人有链接确认,让我知道).但是,对于V4来说,时间仍然是一个因素,并且GUID重复的可能性仍然很小,与任何实际用法无关.你当然不可能只从OP试图做的单一系统测试中生成重复的GUID.

大多数这些答案都缺少关于微软GUID实施的一个重要观点.GUID的第一部分基于时间戳,另一部分基于网卡的MAC地址(如果未安装NIC,则为随机数).

如果我理解正确的话,这意味着复制GUID的唯一可靠方法是在MAC地址相同的多台机器上运行同步GUID代,并且两台系统上的时钟在生成时的确切时间相同发生了(时间戳是基于毫秒,如果我理解正确的话)....即使这样,数字中有很多其他位是随机的,所以赔率仍然很小.

出于所有实际目的,GUID是普遍独特的.

"The Old New Thing"博客上有一个很好的MS GUID描述

  • Raymond在MAC地址部分已经过时了,但微软不再使用这些了.有关V1和V4 Guids之间的区别,请参见http://en.wikipedia.org/wiki/GUID#Algorithm. (8认同)
  • 这在使用虚拟化时实际上是可行的.你可以而且你确实得到了重复的指导. (3认同)

Kri*_*erA 23

这是一个漂亮的小扩展方法,如果你想在代码中的许多地方检查guid唯一性,你可以使用它.

internal static class GuidExt
{
    public static bool IsUnique(this Guid guid)
    {
        while (guid != Guid.NewGuid())
        { }
        return false;
    }
}
Run Code Online (Sandbox Code Playgroud)

要调用它,只需在生成新guid时调用Guid.IsUnique ...

Guid g = Guid.NewGuid();
if (!g.IsUnique())
{
    throw new GuidIsNotUniqueException();
}
Run Code Online (Sandbox Code Playgroud)

...哎呀,我甚至建议两次打电话来确保它在第一轮中正确.

  • 这如何确保在这个世界的任何其他地方都没有生成过"这个guid"?:哎呀,我们需要一个世界的guid池.:) (2认同)

Ste*_*314 19

数到2 ^ 128 - 雄心勃勃.

让我们想象一下,每台机器每秒可以计算2 ^ 32个ID - 不是那么雄心勃勃,因为它甚至不是每秒43亿.让2 ^ 32台机器专门用于该任务.此外,让每个文明都有2 ^ 32个文明将相同的资源专用于任务.

到目前为止,我们每秒可以计算2 ^ 96个ID,这意味着我们将计算2 ^ 32秒(略超过136年).

现在,我们所需要的只是为每台专用的4,294,967,296台机器获得4,294,967,296个文明,每台机器每秒能够计算4,294,967,296个ID,仅在未来136年左右完成这项任务 - 我建议我们立即开始这项重要任务; - )


kib*_*zer 17

好吧,如果830亿年的运行时间不会吓到你,那么你认为你还需要将生成的GUID存储在某处以检查你是否有重复; 存储2 ^ 128个16字节的数字只需要你预先分配4951760157141521099596496896TB的RAM,所以想象你有一台计算机可以适应所有这些并且你以某种方式找到一个地方购买每个10克的太字节DIMM,它们将结合起来重量超过8个地球质量,因此在你按下"运行"之前,你可以认真地将它从当前的轨道上移开.三思而后行!


Nat*_*lor 12

for(begin; begin<end; begin)
    Console.WriteLine(System.Guid.NewGuid().ToString());
Run Code Online (Sandbox Code Playgroud)

你没有增加begin所以条件begin < end总是正确的.

  • 如果他永远循环而不是循环340282366920938463463374607431768211456次真的很重要吗? (3认同)
  • 所以...你宁愿被打得340282366920938463463374607431768211456次或永远!!??!? (3认同)

Mat*_*son 11

如果GUID冲突是一个问题,我建议使用ScottGuID.


MZB*_*MZB 9

据推测,你有理由相信用于生成Guids的算法不会生成真正的随机数,但实际上是以句点<< 2 ^ 128循环.

例如,用于导出GUID的RFC4122方法,该GUID修复了某些位的值.

骑自行车的证明将取决于该时期的可能规模.

对于小周期,散列哈希表(GUID) - > GUID如果GUID不匹配则在碰撞时替换(如果它们这样做则终止)可能是一种方法.考虑也只是替换随机时间的一小部分.

最终,如果碰撞之间的最大周期足够大(并且事先不知道),任何方法只会产生碰撞的概率(如果它存在的话).

请注意,如果生成Guids的方法是基于时钟的(参见RFC),则可能无法确定是否存在冲突,因为(a)您将无法等待足够长的时间来绕回,或者(b)你不能在时钟刻度内请求足够的Guid来强迫碰撞.

或者,您可能能够显示Guid中的位之间的统计关系,或Guids之间的位相关性.这种关系可能使得算法很有可能存在缺陷,而不一定能够找到实际的碰撞.

当然,如果你只是想证明Guids可以碰撞,那么数学证明而不是程序就是答案.


Jas*_*aat 9

但你必须确保你有一个重复的,或者你只关心是否有可能是重复的.为了确保你有两个同一个生日的人,你需要366人(不计算闰年).因为有两个人生日相同的可能性超过50%,你只需要23个人.那是生日问题.

如果您有32位,则只需要77,163个值就有超过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
Run Code Online (Sandbox Code Playgroud)

现在128位是很多,所以你仍然在谈论大量的物品仍然让你碰撞的可能性很小.使用近似值,您将需要以下给定赔率的记录数:

  • 发生碰撞的概率为1/1000亿,为8亿亿
  • 发生碰撞的可能性为217.7亿,为217亿
  • 发生碰撞的概率为396亿亿,为90%

每年发送大约1E14封电子邮件,所以在这个级别上大约有40万年,然后你有90%的机会拥有两个具有相同GUID的电子邮件,但这与你说需要运行计算机的数量有很大不同.在发现重复之前,宇宙的年龄或太阳会变冷.


Dad*_*Dad 8

我不明白为什么没有人提到升级你的显卡...当然如果你有一个高端的NVIDIA Quadro FX 4800或其他东西(192 CUDA核心),这会更快...

当然,如果您能买得起一些NVIDIA Qadro Plex 2200 S4(每个CUDA核心960个),这个计算真的让人大惊小怪.也许NVIDIA会愿意借给你一些"技术示范"作为公关噱头?

当然,他们希望成为这一历史性计算的一部分......


Ant*_*ert 7

难道你不是都错过了一个重点吗?

我认为GUID是使用两个东西生成的,这使得它们在全球范围内的独特性非常高.一个是他们使用您所在机器的MAC地址播种,两个使用它们生成的时间加上一个随机数.

因此,除非您在实际机器上运行它并在机器用于表示GUID中的时间的最短时间内运行所有猜测,否则无论您使用系统调用进行多少猜测,您都不会生成相同的数字.

我想如果你知道制作GUID的实际方式实际上会缩短猜测的时间.

托尼

  • @Martinho:啊,但是在GuidTest.cs中,Mono对Guid的单元测试包含一个创建两个新GUID并检查它们是否相等的方法,如果它们相等就会失败.随着Mono的成功构建,我们可以绝对肯定其GUID是独一无二的!:-) (5认同)
  • 并非所有GUID都来自Windows平台...... (4认同)
  • 并非所有GUID都是以这种方式创建的.即使它们是,Kai也只需要等到用于创建GUID的时间戳包裹足够多次,以便再次使用他用于创建GUID的时间. (3认同)
  • 自2000年或2001年以来,Guids并未基于mac地址.自NT4和/或Win2k的服务包之一起,他们完全改变了算法.它们现在由随机数生成器生成,减去几个位,用于标识它是什么类型的guid. (3认同)

Mic*_*tum 7

您可以散列GUID.这样,你应该更快地得到一个结果.

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


Jim*_*inP 7

  1. 去纽约市的低温实验室.
  2. 冷静(约)1990年.
  3. 在Planet Express找到一份工作.
  4. 购买全新的CPU.构建计算机,运行程序,并使用伪万向运动机器(如世界末日机器)将其放置在安全的地方.
  5. 等到机器发明的时候.
  6. 使用时间机器跳转到未来.如果您购买了1YHz 128位CPU,请3,938,453,320 days 20 hours 15 minutes 38 seconds 463 ms 463 ?s 374 ns 607 ps在开始运行程序后转到.
  7. ...?
  8. 利润!!!

... 10,783,127即使您有1YHz的CPU 1,000,000,000,000,000(或者1,125,899,906,842,624如果您更喜欢使用二进制前缀)比1GHz CPU快一倍,也需要至少几年.

因此,不是等待计算完成,最好喂养失去家园的鸽子,因为其他n鸽子带回家.:(

或者,您可以等到发明128位量子计算机.然后,您可以通过在合理的时间(可能)使用您的程序来证明GUID不是唯一的.


Beh*_*ooz 6

GUIDs are 124 bits because 4 bits hold the version number.