System.Diagnostics.Stopwatch的准确性有多高?

32

System.Diagnostics.Stopwatch的精度有多高?我想为不同的代码路径做一些测量,需要非常准确。我应该使用停表还是有其他更准确的解决方案。

有人告诉我有时候停表会提供不正确的信息。


1
毫秒级的精确度足够吗?对于您的目的来说应该是足够的。请定义“准确”。 - duffymo
我知道它可以给你毫秒级别的时间,但我被告知有很多情况下它并不准确。 - leora
永远不要仅依赖任何单一的测量来获得准确性。运行每个代码路径数分钟并计算迭代次数以获取平均值。 - HUAGHAGUAH
谢谢你的问题。直到现在我都不知道框架中有这样一个类。嘿。 - Ishmaeel
6
我已经写了一篇关于此事的文章。它展示了如何从秒表类中获取准确的测量结果: http://www.codeproject.com/KB/testing/stopwatch-measure-precise.aspx - Thomas Maierhofer
3
顺带一提,由于这是一个非常老的问题,使用新的硬件和较新版本的.NET,在计时器精度方面有了很大改进。正如Lee Grisholm在Kernelman答案评论中所说,现在计时器已经成为QueryPerformanceCounter的包装器。 - ToolmakerSteve
8个回答

22

2
秒写为小写字母s,毫秒写为ms而非mS。请参考维基百科的网页:http://en.wikipedia.org/wiki/Second#SI_multiples(你们文章中也一样)。 - Jannes
你的文章在某种程度上与微软在这里所述的内容相矛盾:https://msdn.microsoft.com/zh-cn/library/windows/desktop/dn553408(v=vs.85).aspx?f=255&MSPPError=-2147217396#Guidance MSDN。他们声称对于大多数硬件,Stopwatch() 是最快和最准确的,特别是对于多处理器 CPU 和频率变化 CPU(这些都是现代 CPU,我想)。如果可能的话,你仍然认为只在一个线程上运行时间管理器是值得的吗? - Philm

7

System.Diagnostics.Stopwatch类确实可以准确地测量时间,但ElapsedTicks方法的工作方式导致一些人得出了不准确的结论,实际上是他们在代码中存在逻辑错误。

一些开发人员认为Stopwatch不准确的原因是,Stopwatch的ElapsedTicks与DateTime中的Ticks不相等。问题出现在应用程序代码使用ElapsedTicks创建新的DateTime时。

var watch = new Stopwatch();
watch.Start();
... (perform a set of operations)
watch.Stop();
var wrongDate = new DateTime(watch.ElapsedTicks); // This is the WRONG value.

如果需要,可以按照以下方式将秒表持续时间转换为DateTime:
// This converts stopwatch ticks into DateTime ticks.
// First convert to TimeSpan, then convert to DateTime
var rightDate = new DateTime(watch.Elapsed.Ticks); 

这里有一篇更详细解释问题的文章:http://geekswithblogs.net/BlackRabbitCoder/archive/2012/01/12/c.net-little-pitfalls-stopwatch-ticks-are-not-timespan-ticks.aspx。请注意,原链接中的内容已不再可用。以下是Wayback Machine存档内容的参考链接:https://web.archive.org/web/20190104073827/http://geekswithblogs.net:80/BlackRabbitCoder/archive/2012/01/12/c.net-little-pitfalls-stopwatch-ticks-are-not-timespan-ticks.aspx

2

2
首先,在谈论时间或空间时,“确切”当然不是可能或有意义的概念,因为对于物理量的任何经验测量都无法假装是精确的。
其次,David Bolton的博客文章可能会有用。我引用他的话:
“如果这是使用高分辨率计数器计时的,那么它将精确到微秒。实际上,它精确到纳秒(10-9秒,即十亿分之一秒),但由于其他很多事情正在进行,纳秒级的精度实际上有点毫无意义。在进行代码的定时或基准测试时,您应该运行多个程序并取平均时间-由于Windows下运行的其他进程,磁盘交换发生了多少等原因,两次运行之间的值可能会有所变化。”

2
主要问题不在于磁盘I/O,而是线程上下文切换。随着.NET框架和Windows的更新版本,这个问题已经变得不那么重要了,但它仍然存在。 - Thomas Maierhofer

1

MSDN有一些示例,展示了秒表的使用。他们还展示了它在纳秒级别上的精度。希望这能对你有所帮助!


1
我运行了他们的示例代码。它说精度可以达到0纳秒,并给出了一个测试结果为-657毫秒。并不是很有帮助! - D'Arcy Rittich
2
精度和准确度并不是同一个东西。你的计算机没有纳秒级的精度,甚至没有毫秒级的精度。 - mmcdole
1
是的,它可以。并非总是如此,但最近的计算机使用RDTSC CPU指令。它可以精确到CPU的频率(例如3 GHz)。然而,我在一些新硬件上遇到了问题,其中StopWatch.Frequency大约为2MHz(因此我猜测Windows正在使用主板上的其他时钟),但由于某种原因,该频率不是很稳定,导致毫秒级误差......这就是为什么我在浏览stackoverflow的原因。 - Jannes

0
除了赞同上面HUAGHAGUAH的建议外,我还要补充一点,你应该非常怀疑微基准测试。虽然密集的性能测试有其合法的地方,但很容易调整不重要的细节。因此,编写和验证旨在可读性和清晰度的代码,然后对其进行分析以找出热点(或是否存在值得担心的热点),然后仅调整这些部分。
我记得曾经与一个程序员一起工作,他微调了一段在系统等待人类输入时执行的代码。时间节省完全消失在按键之间的延迟中!

0

2
请注意,Google Code上的NProf网站表示NProf不再开发 - 它推荐使用SlimTune - Jonathan Leffler
11
有用的信息,但这是针对不同问题的答案。 - A.R.
8
这并没有回答所提出的问题。 - Adam White
1
回复评论时,应回答“不回答问题”的评论:恰恰相反。如果您仔细阅读,这就回答了问题:“我应该使用秒表还是有其他更准确的解决方案”。它只是没有回答问题的标题。除此之外,这里有些人(像我一样)认为改进建议很重要,欢迎回答,并且对我来说,这也包括参考替代解决方案。我有些难以理解,为什么这里似乎有不少人需要批评它(?) - Philm
@Philm:同意,但很遗憾这是“C#秒表分辨率”在谷歌上的最佳搜索结果。 - Ed S.

0
如果您想要更精确的计时,请查看 QueryPerformanceCounter。MSDN 链接:QueryPerformanceCounter。这里提供了一个简洁的实现:here。该示例为 CE 加载 coredll.dll,对于 Windows,您应该按照 MSDN 文档中所述加载 Kernel32.dll。

9
查看 Stopwatch 类的源代码(使用 .NET Reflector),可以发现它实际上只是对 QueryPerformanceCounter 进行了简单的封装。 - Lee Grissom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接