DateTime.Now是衡量函数性能的最好方法吗?

我需要find一个瓶颈,需要尽可能准确地测量时间。

下面的代码片段是衡量性能的最好方法吗?

DateTime startTime = DateTime.Now; // Some execution process DateTime endTime = DateTime.Now; TimeSpan totalTimeTaken = endTime.Subtract(startTime); 

不,这不对。 使用秒表 (在System.Diagnostics

 Stopwatch sw = Stopwatch.StartNew(); PerformWork(); sw.Stop(); Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds); 

秒表自动检查是否存在高精度定时器。

值得一提的是, DateTime.Now往往比DateTime.UtcNow慢得多,因为必须用时区, DST等来完成这项工作。

DateTime.UtcNow通常具有15毫秒的分辨率。 查看约翰·查普曼的博客文章关于DateTime.Now精度为一个伟大的总结。

有趣的琐事:如果您的硬件不支持高频计数器,秒表将返回到DateTime.UtcNow 。 您可以通过查看静态字段Stopwatch.IsHighResolution来查看Stopwatch是否使用硬件来实现高精度。

如果你想快速和肮脏的东西,我会build议使用秒表,而不是更高的精度。

 Stopwatch sw = new Stopwatch(); sw.Start(); // Do Work sw.Stop(); Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds); 

另外,如果你需要更复杂一些的东西,你应该考虑使用第三方分析器,比如ANTS 。

这篇文章说,首先你需要比较三个select, StopwatchDateTime.NowDateTime.UtcNow

这也表明,在某些情况下(当性能计数器不存在时)秒表正在使用DateTime.UtcNow +一些额外的处理。 因为这很明显,在这种情况下,DateTime.UtcNow是最好的select(因为其他使用它+一些处理)

然而,事实certificate,计数器几乎总是存在 – 请参阅有关高分辨率性能计数器的说明及其与.NET Stopwatch相关的存在?

这是一个性能图表。 请注意UtcNow与其他scheme相比性能低下的成本:

在这里输入图像说明

X轴是样本数据大小,Y轴是示例的相对时间。

Stopwatch更好的一点是,它提供了更高分辨率的时间测量。 另一个是它更多的面向对象的性质。 但是,在UtcNow周围创build面向对象的包装并不难。

将基准代码推入实用程序类/方法非常有用。 StopWatch类不需要DisposedStopped错误。 所以,最简单的代码是时间

 public partial class With { public static long Benchmark(Action action) { var stopwatch = Stopwatch.StartNew(); action(); stopwatch.Stop(); return stopwatch.ElapsedMilliseconds; } } 

示例调用代码

 public void Execute(Action action) { var time = With.Benchmark(action); log.DebugFormat(“Did action in {0} ms.”, time); } 

这是扩展方法的版本

 public static class Extensions { public static long Benchmark(this Action action) { return With.Benchmark(action); } } 

和示例调用代码

 public void Execute(Action action) { var time = action.Benchmark() log.DebugFormat(“Did action in {0} ms.”, time); } 

秒表function会更好(精度更高)。 我也build议下载一个stream行的分析器,但( DotTrace和ant是我用过的最多的… DotTrace的免费试用版function齐全,不像其他的一些唠叨)。

使用System.Diagnostics.Stopwatch类。

 Stopwatch sw = new Stopwatch(); sw.Start(); // Do some code. sw.Stop(); // sw.ElapsedMilliseconds = the time your "do some code" took. 

同上秒表,这是更好的方式。

关于性能测量,您还应该检查您的“//某个执行过程”是否是一个非常短的过程。

另外请记住,“//一些执行过程”的第一次运行可能会比后续运行慢。

我通常在一个循环中运行1000次或1000000次来testing一种方法,并且比运行一次更准确的数据。

这些都是衡量时间的好方法,但这只是find瓶颈的非常间接的方法。

在线程中find瓶颈的最直接的方法就是让它运行,并且在做任何事情的时候,用暂停或者中断键来停止它。 多次这样做。 如果你的瓶颈花费了X%的时间,X%是你在每个快照上的行为中捕捉它的概率。

这里有一个更完整的解释如何和为什么它的作品

@ 肖恩·钱伯斯

仅供参考,.NET Timer类不适用于诊断,它会以预设间隔生成事件,如下所示(来自MSDN ):

 System.Timers.Timer aTimer; public static void Main() { // Create a timer with a ten second interval. aTimer = new System.Timers.Timer(10000); // Hook up the Elapsed event for the timer. aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); // Set the Interval to 2 seconds (2000 milliseconds). aTimer.Interval = 2000; aTimer.Enabled = true; Console.WriteLine("Press the Enter key to exit the program."); Console.ReadLine(); } // Specify what you want to happen when the Elapsed event is // raised. private static void OnTimedEvent(object source, ElapsedEventArgs e) { Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime); } 

所以这真的不能帮助你知道一件事花了多长时间,只是有一段时间已经过去了。

定时器也作为System.Windows.Forms中的控件公开…您可以在VS05 / VS08中的devise器工具箱中find它

这是正确的方法:

 using System; using System.Diagnostics; class Program { public static void Main() { Stopwatch stopWatch = Stopwatch.StartNew(); // some other code stopWatch.Stop(); // this not correct to get full timer resolution Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds); // Correct way to get accurate high precision timing Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds); } } 

有关更多信息,请通过使用秒表而不是DataTime获取准确的性能计数器

Visual Studio Team System有一些function可以帮助解决这个问题。 本质上,你可以编写unit testing,并将它们在不同的场景中混合使用,作为压力或负载testing的一部分运行在软件上。 这可能有助于确定最能影响应用程序性能的代码区域。

微软的模式和实践小组在Visual Studio团队系统性能testing指导中有一些指导。

我在Vance Morrison的博客中发现了一篇关于他编写的CodeTimer类的文章, 这个类使得使用StopWatch更简单,并且在一边做了一些简洁的东西。

我做了很less的这种性能检查(我倾向于认为“这很慢,使速度更快”),所以我几乎总是这样做了。

谷歌确实揭示了很多资源/文章进行性能检查。

许多人提到使用pinvoke来获得性能信息。 我学习的很多材料只是提到使用perfmon ..

编辑:

看了StopWatch的会谈..很好! 我学到了东西:)

这看起来像一个很好的文章

我在程序中使用的方式是使用StopWatch类,如下所示。

 Stopwatch sw = new Stopwatch(); sw.Start(); // Critical lines of code long elapsedMs = sw.Elapsed.TotalMilliseconds; 

这不够专业:

 Stopwatch sw = Stopwatch.StartNew(); PerformWork(); sw.Stop(); Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds); 

更可靠的版本是:

 PerformWork(); int repeat = 1000; Stopwatch sw = Stopwatch.StartNew(); for (int i = 0; I < repeat; i ++) { PerformWork(); } sw.Stop(); Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat); 

在我的真实代码中,我将添加GC.Collect调用来将托pipe堆更改为已知状态,并添加Sleep(睡眠)调用,以便在ETWconfiguration文件中轻松分隔不同的代码间隔。