计算方法的执行时间


Answers:


1128

Stopwatch 是为此目的而设计的,并且是衡量.NET中时间执行的最佳方法之一。

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

不要使用DateTime来衡量.NET中的时间执行。


更新:

正如@ series0ne在注释部分所指出的:如果要真正精确地度量某些代码的执行情况,则必须使用操作系统内置的性能计数器。在以下的答案必须包含一个很好的概述。


2
的确如此,这种情况怎么办:我有一个ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); 内部有一个foreach循环,但是秒表在一切完成之前就停止了。
Mahdi Tahsildari 2012年

13
@DarinDimitrov-秒表不完全准确吗?请记住,.NET背景噪音(例如JITing)会导致执行时间发生变化。因此,实际上,为了进行精确的测量,OP应该使用性能分析器。
马修·莱顿

3
@ series0ne,非常好。我将更新我的答案,以包括您的宝贵意见。
Darin Dimitrov

7
@DarinDimitrov,我最近采访了一位非常熟练的高级开发人员。他向我指出,使用DateTimes实际上比使用StopWatch更准确。他说,这样做的原因是.NET中的Stopwatch没有考虑CPU亲和力,因此,如果您的线程从一个内核转移到另一个内核,则StopWatch不会考虑其他内核的执行时间。只有线程开始执行的地方。你对这个有什么看法?
马修·莱顿

2
@ series0ne,高级开发人员告诉您的Stopwatch和DateTime是绝对正确的。除了使用DateTime之外,您没有足够的准确性。问题在于.NET中没有此类可以允许您使用所有这些功能的类。
Darin Dimitrov

75

从个人的经验来看,System.Diagnostics.Stopwatch类可以用来测量方法的执行时间,但是当心:这是不完全准确!

考虑以下示例:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

结果示例

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

现在您想知道;“那为什么第一次要花132ms,而其余时间却少得多?”

答案是Stopwatch不能补偿.NET中的“背景噪声”活动,例如JITing。因此,第一次运行您的方法时,.NET JIT首先。执行此操作所需的时间将添加到执行时间中。同样,其他因素也会导致执行时间发生变化。

您真正需要的绝对精度是性能分析

看一下以下内容:

RedGate ANTS Performance Profiler是一种商业产品,但是可以产生非常准确的结果。- 通过.NET概要分析提高应用程序的性能

这是有关概要分析的StackOverflow文章:- 什么是一些好的.NET Profiler?

我还写了一篇有关使用Stopwatch进行性能分析的文章,您可能想看看-.NET中的性能分析


2
@mahditahsildari没问题。很高兴我能帮上忙!:-)
马修·莱顿

41
我不知道为什么这是一个不准确的例子。秒表正在精确地测量首次呼叫的总成本,这肯定与将要运行此代码的客户有关。他们不在乎是通过方法执行还是在抖动中花费了132毫秒,而是在乎总耗时。
埃里克·利珀特

2
@ series0ne如果您关心循环的性能,请测量循环的性能。不要简单地假设做某事n次意味着它将比执行一次慢n倍。
svick 2012年

3
首先,由于StopWatch永远不会在循环中重置,因此代码示例应产生数量不断增加的输出。“应该”是指(我检查了)。因此您的输出与代码不匹配。其次,当我更正代码以在循环中执行“停止/写入/重置/启动”时,第一次测量与其余测量相同。我的猜测是您的DoSomething在第一次运行时会做更长的时间。JIT可能是原因,也可能不是,但并不是说Stopwatch正在影响测量。因此-1。
ILIA BROUDNO

2
ILIA BROUDNO是绝对正确的,我得到了相同的结果。@ series0ne,循环中有一个Console.WriteLine,到目前为止已写入ms;因为您只在循环结束后才停止计时,所以每次循环都会随着时间的增加而增加,因此随着执行时间的累积,我们应该会看到类似3、6、10、12、15 ...的内容。
Rui Miguel Pinheiro

29

StopWatch 全班寻找您最好的解决方案。

Stopwatch sw = Stopwatch.StartNew();
DoSomeWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

它还有一个称为的静态字段Stopwatch.IsHighResolution。当然,这是硬件和操作系统问题。

指示计时器是否基于高分辨率性能计数器。


18

如果您对了解性能感兴趣,最好的答案是使用探查器。

否则,System.Diagnostics.StopWatch提供一个高分辨率计时器。


完全正确!令我感到沮丧的是,这里有很多人建议使用秒表,因为它并不完全准确。但是,正如您建议使用性能分析器建议的那样,这是正确的方法!+1
马修·莱顿

7

秒表将使用高分辨率计数器

秒表通过计算基础计时器机制中的计时器滴答来测量经过时间。如果安装的硬件和操作系统支持高分辨率性能计数器,则Stopwatch类将使用该计数器来测量经过的时间。否则,秒表类将使用系统计时器来测量经过的时间。使用“频率”和“ IsHighResolution”字段来确定秒表计时实现的精度和分辨率。

如果您要衡量IO,那么您的数据很可能会受到外部事件的影响,我会非常担心。准确性(如上所述)。相反,我将进行一系列测量,并考虑这些数字的均值和分布。


0
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.