2010-10-11 145 views
36

我想测量一段代码的执行情况,我想知道做到这一点的最佳方法是什么?使用C#测量执行时间

选项1:

DateTime StartTime = DateTime.Now; 

//Code 

TimeSpan ts = DateTime.Now.Subtract(StartTime); 
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
Console.WriteLine(elapsedTime, "RunTime"); 

选项2: 使用System.Diagnostics程序;

Stopwatch stopWatch = new Stopwatch(); 
    stopWatch.Start(); 

    //Code 

    stopWatch.Stop(); 
    // Get the elapsed time as a TimeSpan value. 
    TimeSpan ts = stopWatch.Elapsed; 

    // Format and display the TimeSpan value. 
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
     ts.Hours, ts.Minutes, ts.Seconds, 
     ts.Milliseconds/10); 
    Console.WriteLine(elapsedTime, "RunTime"); 

这不仅仅是基准测试,它实际上是应用程序的一部分。函数执行的时间是相关数据。它不需要是原子或超精确的。

哪个选项更适合生产代码,还是其他人使用不同的或者更好的东西?

+0

问得好!我很好奇答案! – 2010-10-11 02:43:33

回答

28

Stopwatch类是专门设计用来测量经过时间,并可能(如果适用于您的硬件)使用底层高频硬件定时器提供了良好的粒度/精度。所以这似乎是最好的选择。

IsHighResolution property可用于确定高分辨率定时是否可用。每文档,这个类提供的“最好的”的Win32 API的精确定时的包装:

具体来说,Frequency场和 GetTimestamp方法可以在 地方的非托管的Win32 API QueryPerformanceFrequency和使用 QueryPerformanceCounter

这些Win32 API [此处]和链接的MSDN文档2上有详细的背景信息。

高分辨率计时器

计数器是在 编程中用于指一个 递增变量的通用术语。一些系统 包括高分辨率性能 计数器,其提供高分辨率 经过的时间。

如果系统中存在一个高分辨率的性能计数器 ,你可以 使用QueryPerformanceFrequency的 功能表达的频率,以每秒 计数。计数值 取决于处理器。例如,在某些 处理器上,计数 可能是处理器时钟的周期速率。

QueryPerformanceCounter的功能 检索 高分辨率性能计数器的当前值。 通过在 代码段的 部分的 的起始和结尾调用此函数,应用程序本质上使用 计数器作为高分辨率 计时器。例如,假设 QueryPerformanceFrequency指示 高分辨率性能计数器的频率为 每秒50,000个计数。如果 应用程序调用 QueryPerformanceCounter的立即 之前,立即进行定时的代码 节过后, 计数器值可能分别为1500个计数 和3500计数。这些 值将指示执行代码 时已经过去.04秒 (2000个计数)。

+0

'Stopwatch'也使用高分辨率定时器(当它可用时),这在测量代码时很重要执行时间短。 – Justin 2010-10-11 03:14:57

+0

@Kragen - 这就是我对底层定时器的意思。我将通过参考Win32 API进行阐述。 – 2010-10-11 12:42:25

+0

请注意,它是'Stopwatch'而不是'StopWatch'(次要的,我知道,但是如果你弄错了,autoresolving依赖关系将不起作用)。 – 2013-05-14 07:45:34

5

既不会影响性能,因为你说它不那么重要。秒表似乎更合适 - 你只是减去时间而不是另一个日期。日期的东西需要更多的内存和CPU时间来处理。还有一些方法可以使代码更清洁,以防计划在多个地方重复使用代码。想起超载using。我会寻找一个例子。

http://stevesmithblog.com/blog/great-uses-of-using-statement-in-c/

public class ConsoleAutoStopWatch : IDisposable 
{ 
    private readonly Stopwatch _stopWatch; 

    public ConsoleAutoStopWatch() 
    { 
     _stopWatch = new Stopwatch(); 
     _stopWatch.Start(); 
    } 

    public void Dispose() 
    { 
     _stopWatch.Stop(); 
     TimeSpan ts = _stopWatch.Elapsed; 

     string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", 
              ts.Hours, ts.Minutes, ts.Seconds, 
              ts.Milliseconds/10); 
     Console.WriteLine(elapsedTime, "RunTime"); 
    } 
} 

private static void UsingStopWatchUsage() 
{ 
    Console.WriteLine("ConsoleAutoStopWatch Used: "); 
    using (new ConsoleAutoStopWatch()) 
    { 
     Thread.Sleep(3000); 
    } 
} 
+0

我不认为需要更多时间。我认为它不太准确,因为它不是用于这种测量。 – codekaizen 2010-10-11 02:48:46

6

我一般用StopWatch对于这种情况:好了,从偷来的代码。

MSDN页:

秒表

提供一组,你可以用它来 准确地测量经过时间的方法和 属性。

在以下文章中,我使用LINQ的执行时间比较VS PLINQ:

Parallel LINQ (PLINQ) with Visual Studio 2010

+0

+1链接到MSDN,我发现它看起来名称已经从'StopWatch'变更为'秒表' – 2012-05-31 17:52:28

1

两者都可能适合您的需求就好了,但我会说使用StopWatch。为什么?因为它意味着你正在做的任务。

你已经有了一个能够返回当前日期/时间的类,它可以用于计时,并且你有一个专门用于计时的类。

在这种情况下,如果你需要毫秒精度(在这种情况下,StopWatch更准确)的区别只是是否真的存在,但如果一个工具,专门存在一般主要的任务你正在寻找那么它的最好的一个使用。

13

这不仅仅是因为StopWatch更准确,而且DateTime.Now在某些情况下会给出不正确的结果。

考虑在夏令时会发生什么情况切换过来,例如—使用DateTime.Now实际上可以给答案!

1

我有一个专门做这种事情的小班。它使用秒表类 - c# micro perfomance testing

例如。

var tester = new PerformanceTester(() => SomeMethod()); 
tester.MeasureExecTime(1000); 
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds)); 
0

使用下面的代码

DateTime dExecutionTime; 
dExecutionTime = DateTime.Now; 
     TimeSpan span = DateTime.Now.Subtract(dExecutionTime); 
        lblExecutinTime.Text = "total time taken " + Math.Round(span.TotalMinutes,2) + " minutes . >>---> " + DateTime.Now.ToShortTimeString(); 
0

我把麦的答案简化它,并使它更一般的情况下,有些则需要登录到别的地方:

public class AutoStopWatch : Stopwatch, IDisposable { 

    public AutoStopWatch() { 
     Start(); 
    } 

    public virtual void Dispose() { 
     Stop(); 
    } 
} 

public class AutoStopWatchConsole : AutoStopWatch { 

    private readonly string prefix; 

    public AutoStopWatchConsole(string prefix = "") { 
     this.prefix = prefix; 
    } 

    public override void Dispose() { 
     base.Dispose(); 

     string format = Elapsed.Days > 0 ? "{0} days " : ""; 
     format += "{1:00}:{2:00}:{3:00}.{4:00}"; 

     Console.WriteLine(prefix + " " + format.Format(Elapsed.Days, Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds, Elapsed.Milliseconds/10)); 
    } 
} 

private static void Usage() { 

    Console.WriteLine("AutoStopWatch Used: "); 
    using (var sw = new AutoStopWatch()) { 
     Thread.Sleep(3000); 

     Console.WriteLine(sw.Elapsed.ToString("h'h 'm'm 's's'")); 
    } 

    Console.WriteLine("AutoStopWatchConsole Used: "); 
    using (var sw = new AutoStopWatchConsole()) { 
     Thread.Sleep(3000); 
    } 

}