秒表可以返回负值是否正常?下面的代码示例可用于重现它。
while (true)
{
Stopwatch sw = new Stopwatch();
sw.Start();
sw.Stop();
if (sw.ElapsedMilliseconds < 0)
Debugger.Break();
}
我可以重现负数的唯一地方是我的虚拟机(由8核机器上的Hyper-V托管)
答案 0 :(得分:17)
这是bug。它似乎没有引起太多关注,因此我建议跟进该报告。
uninspiring workaround似乎是忽略负值:
long elapsedMilliseconds = Math.Max(0, stopwatch.ElapsedMilliseconds);
答案 1 :(得分:11)
我使用Reflector在.NET 2.0和.NET 4.0中反编译了Stopwatch类,然后比较差异以了解它是如何修复的。除了添加新的Restart方法之外,我发现这是差异所在:
public void Stop()
{
if (this.isRunning)
{
long num2 = GetTimestamp() - this.startTimeStamp;
this.elapsed += num2;
this.isRunning = false;
// THE NEXT 4 LINES ARE NEW IN .NET 4.0:
if (this.elapsed < 0L)
{
this.elapsed = 0L;
}
}
}
所以基本上,如果值为负,它们会在Stop方法中设置为0。还有bug恕我直言:
编辑:不幸的是,#2和#3超出了.NET Framework的强大功能:
以下是问题的核心:来自QueryPerformanceCounter上的MSDN,这是秒表类使用的API:
在多处理器计算机上,哪个处理器无关紧要 叫做。但是,您可以在不同的方面获得不同的结果 处理器由于基本输入/输出系统(BIOS)中的错误或 硬件抽象层(HAL)。指定a的处理器关联 线程,使用SetThreadAffinityMask函数。
不要只使用.NET 4.0秒表并假设问题已修复。它不是,除非你希望它们与你的线程亲和力混淆,否则它们无法做任何事情。来自Stopwatch类文档:
在多处理器计算机上,哪个处理器无关紧要 线程运行。但是,由于BIOS或硬件中的错误 抽象层(HAL),您可以获得不同的计时结果 不同处理器。要指定线程的处理器关联,请使用 ProcessThread.ProcessorAffinity方法。
答案 2 :(得分:0)
Microsoft Connect Bug上的“Closed as Fixed”分辨率必须意味着他们在.NET 4中修复了它。我在桌面和VM上运行了repro代码几分钟并且没有负值。
答案 3 :(得分:-1)
我发现在VM中获得正确的已用时间的唯一解决方法是(VB):
Dim tstart AS DateTime = Now
...executing code...
Dim telapsed = (Now - tstart).TotalMilliseconds