是DateTime.Now是测量函数性能的最佳方法吗?

时间:2008-08-26 17:09:45

标签: c# .net performance datetime timer

我需要找到一个瓶颈,并且需要尽可能准确地测量时间。

以下代码段是衡量效果的最佳方法吗?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

16 个答案:

答案 0 :(得分:632)

不,不是。使用Stopwatch(在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毫秒的分辨率。有关精彩摘要的详细信息,请参阅John Chapman's blog post关于DateTime.Now精度。

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

答案 1 :(得分:90)

如果你想要快速和肮脏的东西,我会建议使用秒表来获得更高的精确度。

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

或者,如果您需要更复杂的东西,您应该考虑使用第三方分析器,例如ANTS

答案 2 :(得分:54)

This article表示,首先您需要比较三个备选方案StopwatchDateTime.NowDateTime.UtcNow

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

然而,事实证明,该计数器几乎总是存在 - 请参阅 Explanation about high-resolution performance counter and its existence related to .NET Stopwatch?

这是一张性能图表。请注意UtcNow与替代品相比性能成本如何低:

Enter image description here

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

Stopwatch更好的一点是它提供了更高分辨率的时间测量。另一个是它更具OO性质。但是,围绕UtcNow创建OO包装并不难。

答案 3 :(得分:18)

将基准测试代码推送到实用程序类/方法中非常有用。 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);
}

答案 4 :(得分:16)

stopwatch功能会更好(精度更高)。我还建议只下载一个流行的个人资料,但DotTraceANTS是我最常用的... DotTrace的免费试用功能齐全,不会像其他一些人一样唠叨。)

答案 5 :(得分:13)

使用System.Diagnostics.Stopwatch类。

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

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

答案 6 :(得分:10)

Ditto秒表,它更好。

关于绩效衡量,您还应检查“//一些执行流程”是否是一个非常短的过程。

还要记住,“// Some Execution Process”的第一次运行可能比后续运行慢。

我通常通过在循环中运行1000次或1000000次来测试方法,并且我获得的数据比运行一次更准确。

答案 7 :(得分:9)

这些都是衡量时间的好方法,但这只是找到瓶颈的一种非常间接的方式。

在线程中找到瓶颈的最直接方法是让它运行,当它正在做任何让你等待的事情时,用暂停或中断键停止它。这样做几次。如果您的瓶颈占用X%的时间,则X%是您在每个快照的行为中捕获它的概率。

Here's a more complete explanation of how and why it works

答案 8 :(得分:7)

@ 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.Forms中的控件公开...你可以在VS05 / VS08的设计器工具箱中找到它

答案 9 :(得分:6)

Visual Studio Team System 具有一些可能有助于解决此问题的功能。基本上,您可以编写单元测试并将它们混合在不同的场景中,以作为压力或负载测试的一部分运行。这可能有助于确定最能影响应用程序性能的代码区域。

Microsoft的“模式和实践”小组在 Visual Studio Team System Performance Testing Guidance 中提供了一些指导。

答案 10 :(得分:6)

这是正确的方法:

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);
    }
}

有关详细信息,请浏览 Use Stopwatch instead of DataTime for getting accurate performance counter

答案 11 :(得分:5)

我刚在Vance Morrison的博客中发现了一篇关于a CodeTimer class的帖子,他写道,这使得使用StopWatch变得更容易,并且做了一些简洁的事情。

答案 12 :(得分:4)

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

谷歌确实透露了大量用于性能检查的资源/文章。

许多人提到使用pinvoke来获取性能信息。我研究的很多材料都只提到使用perfmon ..

编辑:

看过StopWatch的谈话..很好!我学到了一些东西:)

This looks like a good article

答案 13 :(得分:4)

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

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


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

答案 14 :(得分:4)

这不够专业:

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 :(得分:0)

由于我不太在乎精度,所以我最终将它们进行了比较。我正在网络上捕获大量数据包,我想安排接收每个数据包的时间。这是测试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");
    }

输出为:

Done executing 5000000 iterations using datetime.now. It took 0.8685502 seconds 
Done executing 5000000 iterations using datetime.utcnow. It took 0.1074324 seconds 
Done executing 5000000 iterations using stopwatch. It took 0.9625021 seconds

因此,总而言之,如果您不太关心精度,则DateTime.UtcNow最快。这也支持该问题的答案https://stackoverflow.com/a/6986472/637142