我需要找到一个瓶颈,并需要尽可能准确地测量时间。
下面的代码片段是衡量性能的最佳方法吗?
DateTime startTime = DateTime.Now;
// Some execution process
DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
#1 楼
不,这不对。使用秒表(在System.Diagnostics
中)Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();
Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);
Stopwatch自动检查是否存在高精度计时器。
值得一提的是
DateTime.Now
由于必须进行时区,DST等工作,因此通常比DateTime.UtcNow
慢很多。DateTime.UtcNow通常具有15毫秒的分辨率。请参见John Chapman的有关
DateTime.Now
精度的博客文章。有趣的琐事:如果您的硬件不支持高频计数器,则秒表将退回到
DateTime.UtcNow
。您可以通过查看静态字段Stopwatch.IsHighResolution来检查Stopwatch是否使用硬件来实现高精度。评论
我要放置一个PerformWork();在秒表“加热”之前。
– DiVan
11年6月23日在8:20
还必须添加建议,如果PerformWork()非常短,则可以重复调用它并计算一批调用的平均值。另外,请对整个通话进行计时,而不要启动/停止秒表,以免产生频闪效应,这种频闪效应会使您的计时测量变得混乱。
– devgeezer
2012年4月11日下午6:24
秒表在多核上不是线程安全的。请参阅stackoverflow.com/questions/6664538/…和stackoverflow.com/questions/1149485/…
– Pavel Savara
2012年7月26日,0:36
sw。经过的毫秒;也能
–Flappy
2014年5月6日11:09
@Pavel,很明显,Microsoft建议秒表是运行Windows 7和Windows 8的现代多核处理器上的最佳解决方案(低开销和高精度)。msdn.microsoft.com/zh-cn/library/windows/桌面/…
–罗恩
15年6月10日在18:04
#2 楼
如果您想要快速又脏的东西,我建议您改用秒表来提高精度。Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();
Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);
或者,如果您需要更高级的功能,则可能应该考虑使用ANTS这样的第三方探查器。
#3 楼
本文说,首先,您需要比较Stopwatch
,DateTime.Now
和DateTime.UtcNow
这三种选择。它还表明,在某些情况下(当性能计数器不存在时),秒表正在使用DateTime.UtcNow +一些额外的处理。因此,很明显在那种情况下DateTime.UtcNow是最好的选择(因为其他人使用它+进行一些处理)
但是,事实证明,计数器几乎总是存在-请参见有关高分辨率性能计数器及其与.NET秒表的关系。
这是一个性能图。请注意,UtcNow与替代产品相比具有较低的性能成本:
X轴是示例数据大小,Y轴是示例的相对时间。 />
Stopwatch
的一个优点是可以提供更高分辨率的时间测量。另一个是其更面向对象的性质。但是,围绕UtcNow
创建OO包装器并不难。评论
第一个链接似乎已断开。
– Peter Mortensen
13年3月22日在20:14
是坏了..时间机器可以显示它,我猜。顺便说一句,为什么您要编辑“三个”,我相信这里并不需要。
– Valentin Kuzub
13年3月22日在20:17
#4 楼
将基准测试代码放入实用程序类/方法中很有用。错误时,StopWatch
类不必是Disposed
或Stopped
。因此,计时某个动作最简单的代码是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);
}
评论
更好的粒度呢?许多事情在不到一毫秒的时间内发生。
–亨里克
2011-2-18在7:32
然后返回Elapsed属性,它是一个TimeSpan。我只是向您展示模式。祝您实施愉快。
– Anthony Mastrean
2011-02-18 13:59
返回Elapsed.TotalMilliseconds以获得更高的精度。参见此问题stackoverflow.com/questions/8894425/…
– nawfal
13年4月12日在6:19
#5 楼
秒表功能会更好(精度更高)。不过,我也建议您下载其中一个最受欢迎的分析器(DotTrace和ANTS是我使用最多的分析器... DotTrace的免费试用版功能齐全,不像其他一些那样na)。#6 楼
使用System.Diagnostics.Stopwatch类。Stopwatch sw = new Stopwatch();
sw.Start();
// Do some code.
sw.Stop();
// sw.ElapsedMilliseconds = the time your "do some code" took.
#7 楼
同上秒表,它会更好。关于性能测量,您还应该检查“ //某些执行过程”是否是很短的过程。
请记住您的“ //某些执行过程”的第一次运行可能比随后的运行慢得多。
我通常通过循环运行1000次或1000000次来测试一种方法,而我得到的更多准确的数据比只运行一次即可。
#8 楼
这些都是测量时间的好方法,但这只是查找瓶颈的一种非常间接的方法。在线程中查找瓶颈的最直接方法是使其运行,并且在做任何让您等待的事情时,请使用暂停或中断键将其暂停。这样做几次。如果您的瓶颈花费了X%的时间,则X%是您在每个快照的动作中都将其捕获的概率。
这里更全面地说明了它如何工作以及为什么起作用
#9 楼
@Sean Chambers仅供参考,.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中作为控件公开。表单...您可以在VS05 / VS08的设计器工具框中找到它
#10 楼
这是正确的方法: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以获得准确的性能计数器。
#11 楼
Visual Studio Team System具有一些有助于解决此问题的功能。本质上,您可以编写单元测试并将其混合在不同的场景中,以作为压力测试或负载测试的一部分针对您的软件运行。这可能有助于确定对您的应用程序性能影响最大的代码区域。Microsoft的“模式和实践”小组在Visual Studio Team System性能测试指南中提供了一些指南。
#12 楼
我刚刚在Vance Morrison的博客中找到有关他编写的CodeTimer类的文章,该类使使用StopWatch
更容易,并且在侧面做了一些整洁的事情。#13 楼
我在程序中使用的方法是使用StopWatch类,如下所示。Stopwatch sw = new Stopwatch();
sw.Start();
// Critical lines of code
long elapsedMs = sw.Elapsed.TotalMilliseconds;
#14 楼
这还不够专业: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调用以将托管堆更改为已知状态,并添加Sleep调用,以便可以在ETW配置文件中轻松分隔不同的代码间隔。
#15 楼
我很少进行这种性能检查(我倾向于只是认为“这很慢,要使其更快”),所以我几乎总是这样做。Google确实显示了很多资源/有关性能检查的文章。
很多人提到使用pinvoke获取性能信息。我学习的许多材料实际上只提到了使用perfmon。.
编辑:
看过StopWatch的话题。。不错!我学到了一些东西:)
这看起来像是一篇不错的文章
#16 楼
由于我不太在乎精度,因此我最终将它们进行了比较。我正在网络上捕获大量数据包,我想安排接收每个数据包的时间。这是测试500万次迭代的代码。输出为: int iterations = 5000000;
// Test using datetime.now
{
var date = DateTime.UtcNow.AddHours(DateTime.UtcNow.Second);
var now = DateTime.UtcNow;
for (int i = 0; i < iterations; i++)
{
if (date == DateTime.Now)
Console.WriteLine("it is!");
}
Console.WriteLine($"Done executing {iterations} iterations using datetime.now. It took {(DateTime.UtcNow - now).TotalSeconds} seconds");
}
// Test using datetime.utcnow
{
var date = DateTime.UtcNow.AddHours(DateTime.UtcNow.Second);
var now = DateTime.UtcNow;
for (int i = 0; i < iterations; i++)
{
if (date == DateTime.UtcNow)
Console.WriteLine("it is!");
}
Console.WriteLine($"Done executing {iterations} iterations using datetime.utcnow. It took {(DateTime.UtcNow - now).TotalSeconds} seconds");
}
// Test using stopwatch
{
Stopwatch sw = new Stopwatch();
sw.Start();
var now = DateTime.UtcNow;
for (int i = 0; i < iterations; i++)
{
if (sw.ElapsedTicks == DateTime.Now.Ticks)
Console.WriteLine("it is!");
}
Console.WriteLine($"Done executing {iterations} iterations using stopwatch. It took {(DateTime.UtcNow - now).TotalSeconds} seconds");
}
因此,总之,如果您不太关心精度,则DateTime.UtcNow是最快的。这也支持该问题的答案https://stackoverflow.com/a/6986472/637142。
评论
顺便说一句,如果您不想要什么,可以使用快速而肮脏的性能计数器。如果需要更高的精度,请使用Stopwatch.GetTimestamp,否则答案很好。
@dbasnett您可以在答案中更详细吗?
在上面的示例中,将start和endtime更改为long,然后将Stopwatch.GetTimestamp分配给它们,而不是DateTime.Now。花费的时间是(结束开始)/ Stopwatch。频率。
“最佳”是主观的。这个问题需要客观地定义“最佳”的含义。