使用 LogTimer 测量时间
如何使用 LogTimer 测量时间并找出应用程序的瓶颈点。
引言
在我上一个项目中,我需要检查是什么减慢了我的应用程序的速度。为了找出行为异常的应用程序的瓶颈,我需要测量几个代码块的执行时间。
虽然 System.Diagnostics.StopWatch
是这个问题的显而易见的解决方案,但它缺少我想要的一些功能
- 测量样本 - 样本是
Start()
及其顺序Stop()
之间的间隔。 - 检索最后一个样本的持续时间 - 虽然
System.Diagnostics.StopWatch
允许测量所有样本的持续时间(所有Start
和Stop
间隔的持续时间),但你不能检索最后一个样本的持续时间(最后一个Start
及其顺序Stop
间隔)。 - 检索总执行时间 - 总执行时间可能有以下含义之一
- 自第一个
Start()
和最后一个Stop()
以来经过的时间 - 自第一个
Start()
和当前时间以来经过的时间
- 自第一个
- 从总执行时间中检索测量的样本时间百分比
- 检索样本的数量(
Start
和Stop
间隔)并查询样本的平均执行时间。
演示程序
演示程序演示了如何使用LogTimer
。我们将测量 DoSomeWork(int timeout)
的执行时间,它只是休眠 timeout 毫秒。计时器数据将在每一步之后显示在控制台上,时间显示为毫秒数。public class LogTimerDemo {
//-------------------------------------------------------------------------
public static void Main(string[] args) {
LogTimerDemo demo = new LogTimerDemo();
LogTimer timer = new LogTimer();
demo.Display(timer,"0");
//-----------------------------------------------------------------------
// Stage 1 : Let measure the exectution time of DoSomeWork(2000)
timer.Start(); demo.DoSomeWork(2000); timer.Stop();
demo.Display(timer,"1");
//-----------------------------------------------------------------------
// Stage 2 - Let wait 3 seconds. Note the influence of AllFromNow property
Thread.Sleep(3000);
timer.AllFromNow = false; demo.Display(timer,"2");
timer.AllFromNow = true; demo.Display(timer,"3");
//-----------------------------------------------------------------------
// Stage 4 : Let measure the exectution time of DoSomeWork(5000)
timer.Start(); demo.DoSomeWork(5000); timer.Stop();
demo.Display(timer,"4");
//-----------------------------------------------------------------------
// Stage 4 : Let measure the exectution's time of calling DoSomeWork(100)
// 100 times in sequence and check the average time DoSomeWork(100). Note
// that we use AddSample() that is more accurate than calling Stop() and
// Start() in sequence.
timer.Reset();
for (int ii = 0;ii > 100;ii++) {
timer.AddSample();
demo.DoSomeWork(100);
}
timer.Stop();
demo.Display(timer,"5");
//-----------------------------------------------------------------------
}
//-------------------------------------------------------------------------
public void DoSomeWork(int ms) {
Thread.Sleep(ms);
}
//-------------------------------------------------------------------------
public void Display(LogTimer timer,string perfix) {
System.Console.WriteLine("{6} => All: {0:D5} , Value: {1:D5} , Current: {2:D5}, Stats: {3,3}%, Average ; {4:D5} [{5} samples]",timer.All.Ms(),timer.Value.Ms(),timer.Current.Ms(),timer.PercentAll,timer.Average.Ms(),timer.Count,perfix);
}
//-------------------------------------------------------------------------
}
这是程序在我机器上的输出
使用 LogTimer
- 你可以通过调用
Start()
来启动一个新样本(开始测量时间)。你也可以在创建新计时器时立即启动计时器,方法是用 true 调用构造函数。虽然允许在计时器运行时(测量时间)调用Start()
,但计时器将忽略它。 - 你可以通过调用
Stop()
来结束样本(停止测量时间)。此函数的返回值是最后一个样本的时间(自上次有效Start()
以来测量的时间)。此样本的时间也会添加到总测量时间中。计时器停止后,你可以调用Start()
以在以后的时间测量其他事件。虽然允许在计时器未运行时(测量时间)调用Stop()
,但计时器将忽略它。 - 你可以通过调用
AddSample
来添加新样本。这与按顺序调用Stop()
和Start
的效果相同,但它更准确。 - 你可以通过调用
Reset()
来重置计时器。如果使用 true 调用,或者通过调用Restart()
,你也可以立即启动计时器。 - 你可以使用
Value
属性来检索总测量时间(所有样本的时间)。如果在计时器运行时调用该属性,则该值将是在属性调用时测量的时间。 - 你可以使用
Current
属性来检索最后一个样本的时间(最后一个Start()
和Stop()
之间的间隔)。如果在计时器运行时调用该属性,则该值将是在属性调用时测量的时间。 - 你可以使用
All
属性来检索总执行时间。此测量的实际含义取决于AllFromNow
属性的值。如果该属性为 true,则该值将是自上次Reset()
后第一次调用Start()
和当前时间之间经过的时间,否则该值将是自上次Reset()
后第一次调用Start()
和最后一次调用Stop()
之间经过的时间。如果在计时器运行时调用该属性,则该值将是在属性调用时测量的时间。 - 你可以使用
Count
属性来检索Start()
和Stop()
间隔的数量。Average
属性是间隔的平均持续时间。(Value
/Count
)