Guid.NewGuid()返回重复?

时间:2008-11-19 01:52:25

标签: c# guid

我们有一个应用程序为我们的某个服务生成模拟数据以进行测试。每个数据项都有一个唯一的Guid。但是,当我们在模拟器的一些次要代码更改后运行测试时,它生成的所有对象都具有相同的Guid。

创建了一个数据对象,然后是一个for循环,其中修改了对象的属性,包括一个新的唯一Guid,并通过远程处理将其发送到服务(serializable,而不是marshal-by-ref,如果这就是你的想法,循环再做一遍等等。

如果我们在循环中放入一个小的Thread.Sleep(...),它会生成唯一的id。我认为这是一个红鲱鱼。我创建了一个测试应用程序,它刚刚创建了一个guid,并且没有一个副本。

我的理论是IL的优化方式导致了这种行为。但足够我的理论。你怎么看?我愿意接受测试的建议和方法。

更新:我的问题似乎有很多混乱,所以让我澄清一下。我不认为NewGuid()被破坏了。显然它有效。没关系!但是某处有一个bug会导致NewGuid(): 1)在我的循环中只调用一次 2)每次在我的循环中调用,但只分配一次 3)我还没有想到的其他东西

这个错误可能出现在我的代码中(可能是MOST)或在某处进行优化。

重申我的问题,我应该如何调试这个场景?

(感谢您的精彩讨论,这真的帮助我在脑海中澄清了这个问题)

更新#2:我想发布一个显示问题的例子,但那是我问题的一部分。我不能在整套应用程序(客户端和服务器)之外复制它。

以下是相关摘录:

OrderTicket ticket = new OrderTicket(... );

for( int i = 0; i < _numOrders; i++ )
{
    ticket.CacheId = Guid.NewGuid();
    Submit( ticket );  // note that this simply makes a remoting call
}

7 个答案:

答案 0 :(得分:21)

提交是否进行异步调用,或者票证对象是否在任何阶段进入另一个线程。

在代码示例中,您将重用相同的对象。如果提交在短暂延迟后在后台线程中发送票证(并且不复制),该怎么办?当您更改CacheId时,实际上正在更新所有挂起的提交。这也解释了为什么Thread.Sleep修复了这个问题。试试这个:

for( int i = 0; i < _numOrders; i++ )
{
    OrderTicket ticket = new OrderTicket(... );
    ticket.CacheId = Guid.NewGuid();
    Submit( ticket );  // note that this simply makes a remoting call
}

如果出于某种原因无法做到这一点,请尝试这一点,看看它们是否仍然相同:

ticket.CacheId = new Guid("00000000-0000-0000-0000-" + 
     string.Format("{0:000000000000}", i));

答案 1 :(得分:6)

成千上万的开发人员在.NET中使用Guids。如果Guid.NewGuid()有任何倾向于“卡住”一个值,很久以前就会遇到这个问题。

次要代码更改是这里的罪魁祸首。事实上Thread.Sleep(不是红色鲱鱼比在阳光下腐烂的鱼)“修复”你的问题表明你的属性被设置为某种奇怪的方式,直到循环停止阻塞才能生效(通过结束或通过Thread.Sleep)。我甚至愿意打赌,“小改动”是从一个单独的线程重置所有属性。

如果您发布了一些示例代码,那将会有所帮助。

答案 2 :(得分:3)

这是您代码中的错误。如果你设法生成多个guid,那么这是最可能的解释。你的问题就在于:“当我们在模拟器的一些小代码更改后运行测试 它生成的所有对象都具有相同的Guid”

答案 3 :(得分:2)

请参阅此article,了解如何创建Guid。

这种艺术来自This回答。

如果你过快地创建GUID并且时钟没有向前移动那么这就是为什么你会得到一些同样的原因。但是当你把睡眠放进去时,因为时钟已经移动了。

答案 4 :(得分:2)

Submit和OrderTicket中的代码也很有用......

您正在重复使用OrderTicket。我怀疑你(或远程本身)正在批处调用 - 可能是关于连接数/主机限制 - 并在最终发送它们时获取CacheId的最后一个值。

如果您调试或Thread.Sleep应用程序,您正在更改时间,以便在分配新的CacheId之前完成远程处理调用。

您是否正在拨打远程电话?我认为同步调用会阻塞 - 但我会检查一下像Wireshark这样的数据包嗅探器。无论如何,只需改变在每次迭代中创建一个新的OrderTicket就可以了。

编辑:关于NewGuid被破坏的问题 ...所以我之前的答案已被删除。

答案 5 :(得分:1)

我不知道如何生成GUID的细节。但是目前我的组织。是以一种让兔子感到羞耻的速度繁殖GUIDs。所以我可以保证 GUID没有被破坏......

  • 如果可能,发布源代码..或克隆repro应用程序。很多时候我发现创建克隆应用程序以重现问题的行为向我展示了这个问题。
  • 另一种方法是评论“那些微小的变化”。如果这可以解决问题,那么您可以进行三角化以找到有问题的代码行。小球的变化很难......我的意思是真的很难。

让我们知道它是怎么回事......这听起来很有趣。

答案 6 :(得分:0)

我的直觉告诉我这些事情正在发生......

class OrderTicket 
{
   Guid CacheId {set {_guid = new Guid("00000000-0000-0000-0000-");}
}

每次使用堆栈跟踪调用时,将CacheId的值记录到日志文件中......也许其他人正在设置它。