10

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

创建了一个数据对象,然后是一个 for 循环,其中对象的属性被修改,包括一个新的唯一 Guid,并通过远程处理(可序列化,而不是 marshal-by-ref,如果这是你的话)发送到服务'正在考虑),循环并再次执行,等等。

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

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

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

这个错误可能在我的代码中(很可能)或在某处的优化中。

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

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

更新#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
}
4

7 回答 7

21

Submit 是否进行异步调用,或者工单对象是否在任何阶段进入另一个线程。

在代码示例中,您正在重用同一个对象。如果 Submit 在短暂延迟后在后台线程中发送票证(并且不获取副本)怎么办。当您更改 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));
于 2008-11-20T00:16:10.707 回答
7

成千上万的开发人员在 .NET 中使用 Guid。如果 Guid.NewGuid() 有任何被“卡”在一个值上的趋势,那么这个问题早就已经遇到了。

小的代码更改是这里的罪魁祸首。Thread.Sleep(与其说是一条在阳光下腐烂的鱼不如说是一条红鲱鱼)“修复”了您的问题这一事实表明您的属性正在以某种奇怪的方式设置,直到循环停止阻塞(或者通过结束或通过 Thread.Sleep)。我什至愿意打赌“微小的变化”是从一个单独的线程中重置所有属性。

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

于 2008-11-19T02:24:37.220 回答
3

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

于 2008-11-19T01:54:36.237 回答
2

请参阅这篇关于如何创建 Guid 的文章。

这篇文章来自这个答案。

最重要的是,如果您创建 GUID 太快并且时钟没有向前移动,这就是为什么您会得到相同的 GUID。但是,当您进入睡眠状态时,它会起作用,因为时钟已经移动。

于 2008-11-19T02:03:29.977 回答
2

Submit 和 OrderTicket 中的代码也会有所帮助......

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

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

您是否正在异步远程调用?我认为同步调用会阻塞 - 但我会使用像 Wireshark 这样的数据包嗅探器来确定。无论如何,只需更改为在每次迭代中创建一个新的 OrderTicket 就可以解决问题。

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

于 2008-11-19T02:21:27.320 回答
1

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

  • 如果可能,请发布源代码.. 或克隆 repro 应用程序。很多时候,我发现创建克隆应用程序来重现问题的行为向我展示了问题。
  • 另一种方法是注释掉“那些微小的变化”。如果这样可以解决问题,则可以进行三角化以找到有问题的代码行。仔细观察细微的变化……我的意思是真正的困难。

一定要告诉我们进展如何……这听起来很有趣。

于 2008-11-19T04:43:49.857 回答
0

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

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

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

于 2008-11-20T00:40:34.217 回答